Revision 4697f1ee

View differences:

src/scheduler/include/ClusterXML.h
43 43
private:
44 44
    int oid;
45 45

  
46
    void init_attributes()
47
    {
48
        xpath(oid, "/CLUSTER/ID", -1);
49
    };
46
    void init_attributes();
47

  
48
    // Configuration attributes
49
    static const char *cluster_paths[]; /**< paths for search function */
50

  
51
    static int cluster_num_paths; /**< number of paths*/
52

  
50 53
};
51 54

  
52 55
#endif /* CLUSTER_XML_H_ */
src/scheduler/include/HostPoolXML.h
45 45
        return static_cast<HostXML *>(PoolXML::get(oid));
46 46
    };
47 47

  
48
    /**
49
     * For each Host in a cluster, adds the cluster template as a new
50
     * Host xml element
51
     *
52
     * @param clpool Cluster pool
53
     */
54
    void merge_clusters(ClusterPoolXML * clpool);
55

  
56 48
protected:
57 49

  
58 50
    int get_suitable_nodes(vector<xmlNodePtr>& content)
src/scheduler/include/HostXML.h
47 47
        return cluster_ids;
48 48
    };
49 49

  
50
    bool is_in_cluster(const set<int> &cids) const
51
    {
52
        set<int>::const_iterator i;
53

  
54
        for (i = cids.begin(); i != cids.end(); i++)
55
        {
56
            if (cluster_ids.find(*i) != cluster_ids.end())
57
            {
58
                return true;
59
            }
60
        }
61

  
62
        return false;
63
    };
64

  
50 65
    /**
51 66
     *  Tests whether a new VM can be hosted by the host or not
52 67
     *    @param cpu needed by the VM (percentage)
src/scheduler/include/VirtualMachineXML.h
116 116
        return ds_requirements;
117 117
    }
118 118

  
119
    const string& get_cluster_requirements()
120
    {
121
        return cluster_requirements;
122
    };
123

  
119 124
    void get_requirements (int& cpu, int& memory, long long& disk,
120 125
        vector<VectorAttribute *> &pci);
121 126

  
......
156 161
    }
157 162

  
158 163
    /**
164
     *  Adds a matching cluster
165
     *    @param oid of the cluster
166
     */
167
    void add_match_cluster(int oid)
168
    {
169
        match_clusters.insert(oid);
170
    }
171

  
172
    /**
159 173
     *  Returns a vector of matched hosts
160 174
     */
161 175
    const vector<Resource *> get_match_hosts()
......
172 186
    }
173 187

  
174 188
    /**
189
     *  Returns a vector of matched hosts
190
     */
191
    const set<int>& get_match_clusters()
192
    {
193
        return match_clusters;
194
    }
195

  
196
    /**
175 197
     *  Sort the matched hosts for the VM
176 198
     */
177 199
    void sort_match_hosts()
......
329 351

  
330 352
    ResourceMatch match_datastores;
331 353

  
354
    set<int> match_clusters;
355

  
332 356
    bool only_public_cloud;
333 357

  
334 358
    /* ----------------------- VIRTUAL MACHINE ATTRIBUTES ------------------- */
......
357 381
    string ds_requirements;
358 382
    string ds_rank;
359 383

  
384
    string cluster_requirements;
385

  
360 386
    VirtualMachineTemplate * vm_template;   /**< The VM template */
361 387
    VirtualMachineTemplate * user_template; /**< The VM user template */
362 388
};
src/scheduler/src/pool/ClusterXML.cc
1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems                */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

  
17
#include "ClusterXML.h"
18

  
19
/* -------------------------------------------------------------------------- */
20
/* -------------------------------------------------------------------------- */
21
int ClusterXML::cluster_num_paths =  2;
22

  
23
const char *ClusterXML::cluster_paths[] = {
24
    "/CLUSTER/TEMPLATE/",
25
    "/CLUSTER/"};
26

  
27
/* -------------------------------------------------------------------------- */
28
/* -------------------------------------------------------------------------- */
29

  
30
void ClusterXML::init_attributes()
31
{
32
    xpath(oid, "/CLUSTER/ID", -1);
33

  
34
    //-------------------- Init search xpath routes ---------------------------
35
    ObjectXML::paths     = cluster_paths;
36
    ObjectXML::num_paths = cluster_num_paths;
37
}
src/scheduler/src/pool/HostPoolXML.cc
95 95

  
96 96
/* -------------------------------------------------------------------------- */
97 97
/* -------------------------------------------------------------------------- */
98

  
99
void HostPoolXML::merge_clusters(ClusterPoolXML * clpool)
100
{
101
    // TODO
102
    /*
103
    map<int,ObjectXML*>::iterator it;
104

  
105
    ClusterXML* cluster;
106
    HostXML*    host;
107

  
108
    int cluster_id;
109
    vector<xmlNodePtr> nodes;
110

  
111
    for (it=objects.begin(); it!=objects.end(); it++)
112
    {
113
        host = static_cast<HostXML*>(it->second);
114

  
115
        cluster_id = host->get_cid();
116

  
117
        if(cluster_id != -1) //ClusterPool::NONE_CLUSTER_ID
118
        {
119
            cluster = clpool->get(cluster_id);
120

  
121
            if(cluster != 0)
122
            {
123
                nodes.clear();
124

  
125
                cluster->get_nodes("/CLUSTER/TEMPLATE", nodes);
126

  
127
                if (!nodes.empty())
128
                {
129
                    host->add_node("/HOST", nodes[0], "CLUSTER_TEMPLATE");
130
                }
131

  
132
                cluster->free_nodes(nodes);
133
            }
134
        }
135
    }
136
    */
137
}
138

  
139
/* -------------------------------------------------------------------------- */
140
/* -------------------------------------------------------------------------- */
src/scheduler/src/pool/HostXML.cc
26 26

  
27 27
/* -------------------------------------------------------------------------- */
28 28
/* -------------------------------------------------------------------------- */
29
int HostXML::host_num_paths =  4;
29
int HostXML::host_num_paths =  3;
30 30

  
31 31
const char *HostXML::host_paths[] = {
32 32
    "/HOST/TEMPLATE/",
33 33
    "/HOST/HOST_SHARE/",
34
    "/HOST/",
35
    "/HOST/CLUSTER_TEMPLATE/"};
34
    "/HOST/"};
36 35

  
37 36
/* -------------------------------------------------------------------------- */
38 37
/* -------------------------------------------------------------------------- */
src/scheduler/src/pool/SConstruct
27 27
    'VirtualMachinePoolXML.cc',
28 28
    'VirtualMachineXML.cc',
29 29
    'ClusterPoolXML.cc',
30
    'ClusterXML.cc',
30 31
    'UserPoolXML.cc',
31 32
    'DatastorePoolXML.cc',
32 33
    'DatastoreXML.cc']
src/scheduler/src/pool/VirtualMachineXML.cc
30 30
    int action;
31 31

  
32 32
    string automatic_requirements;
33
    string automatic_cluster_requirements;
33 34

  
34 35
    xpath(oid, "/VM/ID", -1);
35 36
    xpath(uid, "/VM/UID", -1);
......
92 93
        ds_requirements = automatic_requirements;
93 94
    }
94 95

  
96
    // ------------------- CLUSTER REQUIREMENTS --------------------------------
97

  
98
    xpath(automatic_cluster_requirements, "/VM/TEMPLATE/AUTOMATIC_CLUSTER_REQUIREMENTS", "");
99

  
100
    rc = xpath(cluster_requirements, "/VM/USER_TEMPLATE/SCHED_CLUSTER_REQUIREMENTS", "");
101

  
102
    if (rc == 0)
103
    {
104
        if ( !automatic_cluster_requirements.empty() )
105
        {
106
            ostringstream oss;
107

  
108
            oss << automatic_cluster_requirements << " & ( " << cluster_requirements << " )";
109

  
110
            cluster_requirements = oss.str();
111
        }
112
    }
113
    else if ( !automatic_cluster_requirements.empty() )
114
    {
115
        cluster_requirements = automatic_cluster_requirements;
116
    }
117

  
95 118
    // ---------------- HISTORY HID, DSID, RESCHED & TEMPLATE ------------------
96 119

  
97 120
    xpath(hid,  "/VM/HISTORY_RECORDS/HISTORY/HID", -1);
src/scheduler/src/sched/Scheduler.cc
472 472
    }
473 473

  
474 474
    //--------------------------------------------------------------------------
475
    //Add to each host the corresponding cluster template
476
    //--------------------------------------------------------------------------
477

  
478
    hpool->merge_clusters(clpool);
479

  
480
    //--------------------------------------------------------------------------
481 475
    //Cleans the cache and get the ACLs
482 476
    //--------------------------------------------------------------------------
483 477

  
......
513 507
 *  @param n_error number of requirement errors, incremented if needed
514 508
 *  @param n_fits number of hosts with capacity that fits the VM requirements
515 509
 *  @param n_matched number of hosts that fullfil VM sched_requirements
510
 *  @param n_cluster_matched number of hosts that fulfill VM sched_cluster_requirements
516 511
 *  @param error, string describing why the host is not valid
517 512
 *  @return true for a positive match
518 513
 */
519 514
static bool match_host(AclXML * acls, UserPoolXML * upool, VirtualMachineXML* vm,
520 515
    int vmem, int vcpu, vector<VectorAttribute *>& vpci, HostXML * host,
521
    int &n_auth, int& n_error, int &n_fits, int &n_matched, string &error)
516
    int &n_auth, int& n_error, int &n_fits, int &n_matched,
517
    int &n_cluster_matched, string &error)
522 518
{
523 519
    // -------------------------------------------------------------------------
524 520
    // Filter current Hosts for resched VMs
......
571 567
    n_auth++;
572 568

  
573 569
    // -------------------------------------------------------------------------
570
    // Check host clusters
571
    // -------------------------------------------------------------------------
572

  
573
    if (host->is_in_cluster(vm->get_match_clusters()) != true)
574
    {
575
        error = "Host is not in any of the filtered Clusters.";
576
        return false;
577
    }
578

  
579
    n_cluster_matched++;
580

  
581
    // -------------------------------------------------------------------------
574 582
    // Check host capacity
575 583
    // -------------------------------------------------------------------------
576 584
    if (host->test_capacity(vcpu, vmem, vpci, error) != true)
......
635 643
 *  @param n_error number of requirement errors, incremented if needed
636 644
 *  @param n_matched number of system ds that fullfil VM sched_requirements
637 645
 *  @param n_fits number of system ds with capacity that fits the VM requirements
646
 *  @param n_cluster_matched number of system ds that fulfill VM sched_cluster_requirements
638 647
 *  @param error, string describing why the host is not valid
639 648
 *  @return true for a positive match
640 649
 */
641 650
static bool match_system_ds(AclXML * acls, UserPoolXML * upool,
642 651
    VirtualMachineXML* vm, long long vdisk, DatastoreXML * ds, int& n_auth,
643
    int& n_error, int& n_fits, int &n_matched, string &error)
652
    int& n_error, int& n_fits, int &n_matched,
653
    int &n_cluster_matched, string &error)
644 654
{
645 655
    // -------------------------------------------------------------------------
646 656
    // Check if user is authorized
......
673 683
    n_auth++;
674 684

  
675 685
    // -------------------------------------------------------------------------
686
    // Check host clusters
687
    // -------------------------------------------------------------------------
688

  
689
    if (ds->is_in_cluster(vm->get_match_clusters()) != true)
690
    {
691
        error = "System DS is not in any of the filtered Clusters.";
692
        return false;
693
    }
694

  
695
    n_cluster_matched++;
696

  
697
    // -------------------------------------------------------------------------
676 698
    // Check datastore capacity for shared systems DS (non-shared will be
677 699
    // checked in a per host basis during dispatch). Resume actions do not
678 700
    // add to shared system DS usage, and are skipped also
......
720 742
}
721 743

  
722 744
/* -------------------------------------------------------------------------- */
745
/* -------------------------------------------------------------------------- */
746

  
747
/**
748
 *  Match clusters for this VM that:
749
 *    1. Meet user/automatic requirements
750
 *
751
 *  @param vm the virtual machine
752
 *  @param cluster to evaluate vm assignment
753
 *  @param n_error number of requirement errors
754
 *  @param n_matched number of clusters that fulfill VM sched_cluster_requirements
755
 *  @param error, string describing why the cluster is not valid
756
 *  @return true for a positive match
757
 */
758
static bool match_cluster(VirtualMachineXML* vm, ClusterXML * cluster,
759
        int& n_error, int &n_matched, string &error)
760
{
761
    // -------------------------------------------------------------------------
762
    // Evaluate VM requirements
763
    // -------------------------------------------------------------------------
764
    if (!vm->get_cluster_requirements().empty())
765
    {
766
        char * estr;
767
        bool   matched;
768

  
769
        if ( cluster->eval_bool(vm->get_cluster_requirements(), matched, &estr) != 0 )
770
        {
771
            ostringstream oss;
772

  
773
            n_error++;
774

  
775
            oss << "Error in SCHED_CLUSTER_REQUIREMENTS: '"
776
                << vm->get_cluster_requirements() << "', error: " << error;
777

  
778
            vm->log(oss.str());
779

  
780
            free(estr);
781
        }
782

  
783
        if (matched == false)
784
        {
785
            ostringstream oss;
786

  
787
            oss << "It does not fulfill SCHED_CLUSTER_REQUIREMENTS: "
788
                << vm->get_cluster_requirements();
789
            error = oss.str();
790

  
791
            return false;
792
        }
793
    }
794

  
795
    n_matched++;
796

  
797
    return true;
798
}
799

  
800
/* -------------------------------------------------------------------------- */
723 801

  
724 802
static void log_match(int vid, const string& msg)
725 803
{
......
747 825
    int n_auth;
748 826
    int n_error;
749 827
    int n_fits;
828
    int n_cluster_matched;
750 829

  
830
    ClusterXML * cluster;
751 831
    HostXML * host;
752 832
    DatastoreXML *ds;
753 833

  
754 834
    string m_error;
755 835

  
756 836
    map<int, ObjectXML*>::const_iterator  vm_it;
757
    map<int, ObjectXML*>::const_iterator  h_it;
837
    map<int, ObjectXML*>::const_iterator  obj_it;
758 838

  
759 839
    vector<SchedulerPolicy *>::iterator it;
760 840

  
761 841
    const map<int, ObjectXML*> pending_vms = vmpool->get_objects();
842
    const map<int, ObjectXML*> clusters    = clpool->get_objects();
762 843
    const map<int, ObjectXML*> hosts       = hpool->get_objects();
763 844
    const map<int, ObjectXML*> datastores  = dspool->get_objects();
764 845
    const map<int, ObjectXML*> users       = upool->get_objects();
765 846

  
766
    double total_match_time = 0;
767
    double total_rank_time = 0;
847
    double total_cl_match_time = 0;
848
    double total_host_match_time = 0;
849
    double total_host_rank_time = 0;
850
    double total_ds_match_time = 0;
851
    double total_ds_rank_time = 0;
768 852

  
769 853
    time_t stime = time(0);
770 854

  
......
804 888
        }
805 889

  
806 890
        // ---------------------------------------------------------------------
891
        // Match clusters for this VM.
892
        // ---------------------------------------------------------------------
893
        profile(true);
894

  
895
        for (obj_it=clusters.begin(); obj_it != clusters.end(); obj_it++)
896
        {
897
            cluster = static_cast<ClusterXML *>(obj_it->second);
898

  
899
            if (match_cluster(vm, cluster, n_error, n_matched, m_error))
900
            {
901
                vm->add_match_cluster(cluster->get_oid());
902

  
903
                n_resources++;
904
            }
905
            else
906
            {
907
                if ( n_error > 0 )
908
                {
909
                    log_match(vm->get_oid(), "Cannot schedule VM. " + m_error);
910
                    break;
911
                }
912
                else if (NebulaLog::log_level() >= Log::DDEBUG)
913
                {
914
                    ostringstream oss;
915
                    oss << "Hosts and System DS in Cluster "
916
                        << cluster->get_oid() << " discarded for VM "
917
                        << vm->get_oid() << ". " << m_error;
918

  
919
                    NebulaLog::log("SCHED", Log::DDEBUG, oss);
920
                }
921
            }
922
        }
923

  
924
        total_cl_match_time += profile(false);
925

  
926
        // ---------------------------------------------------------------------
927
        // Log scheduling errors to VM user if any
928
        // ---------------------------------------------------------------------
929

  
930
        if (n_resources == 0) //No clusters assigned, let's see why
931
        {
932
            // TODO
933
        }
934

  
935
        // ---------------------------------------------------------------------
807 936
        // Match hosts for this VM.
808 937
        // ---------------------------------------------------------------------
809 938
        profile(true);
810 939

  
811
        for (h_it=hosts.begin(); h_it != hosts.end(); h_it++)
940
        for (obj_it=hosts.begin(); obj_it != hosts.end(); obj_it++)
812 941
        {
813
            host = static_cast<HostXML *>(h_it->second);
942
            host = static_cast<HostXML *>(obj_it->second);
814 943

  
815 944
            if (match_host(acls, upool, vm, vm_memory, vm_cpu, vm_pci, host,
816
                    n_auth, n_error, n_fits, n_matched, m_error))
945
                    n_auth, n_error, n_fits, n_matched, n_cluster_matched, m_error))
817 946
            {
818 947
                vm->add_match_host(host->get_hid());
819 948

  
......
837 966
            }
838 967
        }
839 968

  
840
        total_match_time += profile(false);
969
        total_host_match_time += profile(false);
841 970

  
842 971
        // ---------------------------------------------------------------------
843 972
        // Log scheduling errors to VM user if any
......
855 984
                {
856 985
                    vm->log("User is not authorized to use any host");
857 986
                }
987
                else if (n_cluster_matched == 0)
988
                {
989
                    ostringstream oss;
990

  
991
                    oss << "No host meets capacity and SCHED_CLUSTER_REQUIREMENTS: "
992
                        << vm->get_cluster_requirements();
993

  
994
                    vm->log(oss.str());
995
                }
858 996
                else if (n_fits == 0)
859 997
                {
860 998
                    ostringstream oss;
......
893 1031

  
894 1032
        vm->sort_match_hosts();
895 1033

  
896
        total_rank_time += profile(false);
1034
        total_host_rank_time += profile(false);
897 1035

  
898 1036
        if (vm->is_resched())//Will use same system DS for migrations
899 1037
        {
......
906 1044
        // Match datastores for this VM
907 1045
        // ---------------------------------------------------------------------
908 1046

  
1047
        profile(true);
1048

  
909 1049
        n_resources = 0;
910 1050
        n_auth    = 0;
911 1051
        n_matched = 0;
912 1052
        n_error   = 0;
913 1053
        n_fits    = 0;
914 1054

  
915
        for (h_it=datastores.begin(); h_it != datastores.end(); h_it++)
1055
        for (obj_it=datastores.begin(); obj_it != datastores.end(); obj_it++)
916 1056
        {
917
            ds = static_cast<DatastoreXML *>(h_it->second);
1057
            ds = static_cast<DatastoreXML *>(obj_it->second);
918 1058

  
919 1059
            if (match_system_ds(acls, upool, vm, vm_disk, ds, n_auth, n_error,
920
                        n_fits, n_matched, m_error))
1060
                        n_fits, n_matched, n_cluster_matched, m_error))
921 1061
            {
922 1062
                vm->add_match_datastore(ds->get_oid());
923 1063

  
......
941 1081
            }
942 1082
        }
943 1083

  
1084
        total_ds_match_time += profile(false);
1085

  
944 1086
        // ---------------------------------------------------------------------
945 1087
        // Log scheduling errors to VM user if any
946 1088
        // ---------------------------------------------------------------------
......
965 1107
                    {
966 1108
                        vm->log("User is not authorized to use any system datastore");
967 1109
                    }
1110
                    else if (n_cluster_matched == 0)
1111
                    {
1112
                        ostringstream oss;
1113

  
1114
                        oss << "No system datastore meets capacity and "
1115
                            << "SCHED_CLUSTER_REQUIREMENTS: "
1116
                            << vm->get_cluster_requirements();
1117

  
1118
                        vm->log(oss.str());
1119
                    }
968 1120
                    else if (n_fits == 0)
969 1121
                    {
970 1122
                        ostringstream oss;
......
999 1151
        // Schedule matched datastores
1000 1152
        // ---------------------------------------------------------------------
1001 1153

  
1154
        profile(true);
1155

  
1002 1156
        for (it=ds_policies.begin() ; it != ds_policies.end() ; it++)
1003 1157
        {
1004 1158
            (*it)->schedule(vm);
1005 1159
        }
1006 1160

  
1007 1161
        vm->sort_match_datastores();
1162

  
1163
        total_ds_rank_time += profile(false);
1008 1164
    }
1009 1165

  
1010
    ostringstream oss;
1166
    if (NebulaLog::log_level() >= Log::DDEBUG)
1167
    {
1168
        ostringstream oss;
1011 1169

  
1012
    oss << "Match Making statistics:\n"
1013
        << "\tNumber of VMs: \t\t" << pending_vms.size() << endl
1014
        << "\tTotal time: \t\t" << one_util::float_to_str(time(0) - stime) << "s" << endl
1015
        << "\tTotal Match time: \t" << one_util::float_to_str(total_match_time) << "s" << endl
1016
        << "\tTotal Ranking time: \t" << one_util::float_to_str(total_rank_time) << "s";
1170
        oss << "Match Making statistics:\n"
1171
            << "\tNumber of VMs:            " << pending_vms.size() << endl
1172
            << "\tTotal time:               " << one_util::float_to_str(time(0) - stime) << "s" << endl
1173
            << "\tTotal Cluster Match time: " << one_util::float_to_str(total_cl_match_time) << "s" << endl
1174
            << "\tTotal Host Match time:    " << one_util::float_to_str(total_host_match_time) << "s" << endl
1175
            << "\tTotal Host Ranking time:  " << one_util::float_to_str(total_host_rank_time) << "s" << endl
1176
            << "\tTotal DS Match time:      " << one_util::float_to_str(total_ds_match_time) << "s" << endl
1177
            << "\tTotal DS Ranking time:    " << one_util::float_to_str(total_ds_rank_time) << "s" << endl;
1017 1178

  
1018
    NebulaLog::log("SCHED", Log::DDEBUG, oss);
1179
        NebulaLog::log("SCHED", Log::DDEBUG, oss);
1180
    }
1019 1181

  
1020 1182
    if (NebulaLog::log_level() >= Log::DDDEBUG)
1021 1183
    {
src/vm/VirtualMachine.cc
1462 1462

  
1463 1463
    if ( !cluster_ids.empty() )
1464 1464
    {
1465
        // TODO: create a separate cluster automatic requirements
1466
        oss << "CLUSTER_IDS = " << one_util::join(cluster_ids, ',')
1467
            << " & !(PUBLIC_CLOUD = YES)";
1468
    }
1469
    else
1470
    {
1471
        oss << "!(PUBLIC_CLOUD = YES)";
1465
        set<int>::iterator i = cluster_ids.begin();
1466

  
1467
        oss << "(ID = " << *i;
1468

  
1469
        for (++i; i != cluster_ids.end(); i++)
1470
        {
1471
            oss << " | ID = " << *i;
1472
        }
1473

  
1474
        oss << ")";
1475

  
1476
        obj_template->add("AUTOMATIC_CLUSTER_REQUIREMENTS", oss.str());
1472 1477
    }
1473 1478

  
1479
    oss.str("");
1480
    oss << "!(PUBLIC_CLOUD = YES)";
1481

  
1474 1482
    if (num_public != 0)
1475 1483
    {
1476 1484
        set<string>::iterator it = clouds.begin();

Also available in: Unified diff