Beispiel #1
0
    def delete(self, host_id, subkey):
        """
        Delete one attribute in configuration of a specific cluster host
        :param host_id: the cluster host ID
        :param subkey: the attribute name in configuration
        """
        available_delete_keys = ['ip', 'role']
        with database.session() as session:
            host = session.query(ModelClusterHost).filter_by(id=host_id)\
                                                  .first()
            if not host:
                error_msg = "The host id=%s does not exist!" % host_id
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))

            if subkey not in available_delete_keys:
                error_msg = "subkey %s is not supported!" % subkey
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            if not host.mutable:
                error_msg = "The host 'id=%s' is not mutable!" % host_id
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            config = json.loads(host.config_data)
            # Set the subkey's value to ""
            util.update_dict_value(subkey, "", config)
            host.config = config

        return util.make_json_response(
            200, {"status": "OK"})
Beispiel #2
0
    def delete(self, host_id, subkey):
        """
        Delete one attribute in configuration of the specified cluster host

        :param host_id: the unique identifier of the host
        :param subkey: the attribute name in configuration
        """
        available_delete_keys = ['ip', 'roles']
        with database.session() as session:
            host = session.query(ModelClusterHost).filter_by(id=host_id)\
                                                  .first()
            if not host:
                error_msg = "The host id=%s does not exist!" % host_id
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))

            if subkey not in available_delete_keys:
                error_msg = "subkey %s is not supported!" % subkey
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            if not host.mutable:
                error_msg = "The host 'id=%s' is not mutable!" % host_id
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            config = json.loads(host.config_data)
            # Set the subkey's value to ""
            util.update_dict_value(subkey, "", config)
            host.config = config

        return util.make_json_response(200, {"status": "OK"})
Beispiel #3
0
    def put(self, cluster_id, resource):
        """
        Update the resource information of the specified cluster in database

        :param cluster_id: the unique identifier of the cluster
        :param resource: resource name(security, networking, partition)
        """
        resources = {
            self.SECURITY: {
                'validator': 'is_valid_security_config',
                'column': 'security_config'
            },
            self.NETWORKING: {
                'validator': 'is_valid_networking_config',
                'column': 'networking_config'
            },
            self.PARTITION: {
                'validator': 'is_valid_partition_config',
                'column': 'partition_config'
            },
        }
        request_data = json.loads(request.data)
        with database.session() as session:
            cluster = session.query(ModelCluster).filter_by(id=cluster_id)\
                                                 .first()

            if not cluster:
                error_msg = 'You are trying to update a non-existing cluster!'
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))
            if resource not in request_data:
                error_msg = "Invalid resource name '%s'" % resource
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            value = request_data[resource]

            if resource not in resources.keys():
                error_msg = "Invalid resource name '%s'" % resource
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            validate_func = resources[resource]['validator']
            module = globals()['util']
            is_valid, msg = getattr(module, validate_func)(value)

            if is_valid:
                column = resources[resource]['column']
                session.query(ModelCluster).filter_by(id=cluster_id)\
                       .update({column: json.dumps(value)})
            else:
                return errors.handle_mssing_input(
                    errors.InputMissingError(msg))

        return util.make_json_response(200, {"status": "OK"})
Beispiel #4
0
    def put(self, host_id):
        """
        Update configuration of the specified cluster host

        :param host_id: the unique identifier of the host
        """
        with database.session() as session:
            host = session.query(ModelClusterHost).filter_by(id=host_id)\
                                                  .first()
            if not host:
                error_msg = "The host id=%s does not exist!" % host_id
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))
            logging.debug("cluster config put request.data %s", request.data)
            request_data = json.loads(request.data)
            if not request_data:
                error_msg = "request data is %s" % request_data
                return errors.handle_mssing_input(
                    errors.InputMissingError(error_msg))

            if not host.mutable:
                error_msg = "The host 'id=%s' is not mutable!" % host_id
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            #Valid if keywords in request_data are all correct
            if 'hostname' in request_data:
                hostname = request_data['hostname']
                cluster_id = host.cluster_id
                test_host = session.query(ModelClusterHost)\
                                   .filter_by(cluster_id=cluster_id,
                                              hostname=hostname).first()
                if test_host:
                    error_msg = ("Hostname '%s' has been used for other host "
                                 "in the cluster, cluster ID is %s!"
                                 % (hostname, cluster_id))

                    return errors.handle_invalid_usage(
                        errors.UserInvalidUsage(error_msg))

                session.query(ModelClusterHost).filter_by(id=host_id)\
                       .update({"hostname": request_data['hostname']})
                del request_data['hostname']

            try:
                util.valid_host_config(request_data)
            except errors.UserInvalidUsage as exc:
                return errors.handle_invalid_usage(exc)

            host.config = request_data

            return util.make_json_response(
                200, {"status": "OK"})
Beispiel #5
0
    def put(self, cluster_id, resource):
        """
        Update the resource information of the specified cluster in database

        :param cluster_id: the unique identifier of the cluster
        :param resource: resource name(security, networking, partition)
        """
        resources = {
            self.SECURITY: {'validator': 'is_valid_security_config',
                            'column': 'security_config'},
            self.NETWORKING: {'validator': 'is_valid_networking_config',
                              'column': 'networking_config'},
            self.PARTITION: {'validator': 'is_valid_partition_config',
                             'column': 'partition_config'},
        }
        request_data = json.loads(request.data)
        with database.session() as session:
            cluster = session.query(ModelCluster).filter_by(id=cluster_id)\
                                                 .first()

            if not cluster:
                error_msg = 'You are trying to update a non-existing cluster!'
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg)
                    )
            if resource not in request_data:
                error_msg = "Invalid resource name '%s'" % resource
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            value = request_data[resource]

            if resource not in resources.keys():
                error_msg = "Invalid resource name '%s'" % resource
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            validate_func = resources[resource]['validator']
            module = globals()['util']
            is_valid, msg = getattr(module, validate_func)(value)

            if is_valid:
                column = resources[resource]['column']
                session.query(ModelCluster).filter_by(id=cluster_id)\
                       .update({column: json.dumps(value)})
            else:
                return errors.handle_mssing_input(
                    errors.InputMissingError(msg))

        return util.make_json_response(
            200, {"status": "OK"})
Beispiel #6
0
    def post(self):
        """
        Insert switch IP and the credential to db. Invoke a task to poll
        switch at the same time.

        :param ip: switch IP address
        :param credential: a dict for accessing the switch
        """
        ip_addr = None
        credential = None
        logging.debug('post switch request from curl is %s', request.data)
        json_data = json.loads(request.data)
        ip_addr = json_data['switch']['ip']
        credential = json_data['switch']['credential']

        logging.info('post switch ip_addr=%s credential=%s(%s)', ip_addr,
                     credential, type(credential))

        if not util.is_valid_ip(ip_addr):
            error_msg = "Invalid IP address format!"
            return errors.handle_invalid_usage(
                errors.UserInvalidUsage(error_msg))

        new_switch = {}
        with database.session() as session:
            switch = session.query(ModelSwitch).filter_by(ip=ip_addr).first()
            logging.info('switch for ip %s: %s', ip_addr, switch)

            if switch:
                error_msg = "IP address '%s' already exists" % ip_addr
                value = {'failedSwitch': switch.id}
                return errors.handle_duplicate_object(
                    errors.ObjectDuplicateError(error_msg), value)

            switch = ModelSwitch(ip=ip_addr)
            switch.credential = credential
            session.add(switch)
            session.flush()
            new_switch['id'] = switch.id
            new_switch['ip'] = switch.ip
            new_switch['state'] = switch.state
            link = {
                'rel': 'self',
                'href': '/'.join((self.ENDPOINT, str(switch.id)))
            }
            new_switch['link'] = link

        celery.send_task("compass.tasks.pollswitch", (ip_addr, ))
        logging.info('new switch added: %s', new_switch)
        return util.make_json_response(202, {
            "status": "accepted",
            "switch": new_switch
        })
Beispiel #7
0
    def post(self):
        """
        Insert switch IP and the credential to db. Invoke a task to poll
        switch at the same time.

        :param ip: switch IP address
        :param credential: a dict for accessing the switch
        """
        ip_addr = None
        credential = None
        logging.debug('post switch request from curl is %s', request.data)
        json_data = json.loads(request.data)
        ip_addr = json_data['switch']['ip']
        credential = json_data['switch']['credential']

        logging.info('post switch ip_addr=%s credential=%s(%s)',
                     ip_addr, credential, type(credential))

        if not util.is_valid_ip(ip_addr):
            error_msg = "Invalid IP address format!"
            return errors.handle_invalid_usage(
                errors.UserInvalidUsage(error_msg)
                )

        new_switch = {}
        with database.session() as session:
            switch = session.query(ModelSwitch).filter_by(ip=ip_addr).first()
            logging.info('switch for ip %s: %s', ip_addr, switch)

            if switch:
                error_msg = "IP address '%s' already exists" % ip_addr
                value = {'failedSwitch': switch.id}
                return errors.handle_duplicate_object(
                    errors.ObjectDuplicateError(error_msg), value
                )

            switch = ModelSwitch(ip=ip_addr)
            switch.credential = credential
            session.add(switch)
            session.flush()
            new_switch['id'] = switch.id
            new_switch['ip'] = switch.ip
            new_switch['state'] = switch.state
            link = {'rel': 'self',
                    'href': '/'.join((self.ENDPOINT, str(switch.id)))}
            new_switch['link'] = link

        celery.send_task("compass.tasks.pollswitch", (ip_addr,))
        logging.info('new switch added: %s', new_switch)
        return util.make_json_response(
            202, {"status": "accepted",
                  "switch":  new_switch}
            )
Beispiel #8
0
    def put(self, host_id):
        """
        Update configuration of the specified cluster host

        :param host_id: the unique identifier of the host
        """
        with database.session() as session:
            host = session.query(ModelClusterHost).filter_by(id=host_id)\
                                                  .first()
            if not host:
                error_msg = "The host id=%s does not exist!" % host_id
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))
            logging.debug("cluster config put request.data %s", request.data)
            request_data = json.loads(request.data)
            if not request_data:
                error_msg = "request data is %s" % request_data
                return errors.handle_mssing_input(
                    errors.InputMissingError(error_msg))

            if not host.mutable:
                error_msg = "The host 'id=%s' is not mutable!" % host_id
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            #Valid if keywords in request_data are all correct
            if 'hostname' in request_data:
                session.query(ModelClusterHost).filter_by(id=host_id)\
                       .update({"hostname": request_data['hostname']})
                del request_data['hostname']

            try:
                util.valid_host_config(request_data)
            except errors.UserInvalidUsage as exc:
                return errors.handle_invalid_usage(exc)

            host.config = request_data

            return util.make_json_response(200, {"status": "OK"})
Beispiel #9
0
    def get(self, cluster_id, resource=None):
        """
        Lists details of the specified cluster if resource is not specified.
        Otherwise, lists details of the resource of this cluster

        :param cluster_id: the unique identifier of the cluster
        :param resource: the resource name(security, networking, partition)
        """
        cluster_resp = {}
        resp = {}
        with database.session() as session:
            cluster = session.query(ModelCluster)\
                             .filter_by(id=cluster_id)\
                             .first()
            logging.debug('cluster is %s', cluster)
            if not cluster:
                error_msg = 'Cannot found the cluster with id=%s' % cluster_id
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg)
                    )

            if resource:
                # List resource details
                if resource == self.SECURITY:
                    cluster_resp = cluster.security
                elif resource == self.NETWORKING:
                    cluster_resp = cluster.networking
                elif resource == self.PARTITION:
                    cluster_resp = cluster.partition
                else:
                    error_msg = "Invalid resource name '%s'!" % resource
                    return errors.handle_invalid_usage(
                        errors.UserInvalidUsage(error_msg)
                    )
                resp = {"status": "OK",
                        resource: cluster_resp}

            else:
                cluster_resp['clusterName'] = cluster.name
                cluster_resp['link'] = {
                    'rel': 'self',
                    'href': '/'.join((self.ENDPOINT, str(cluster.id)))
                }
                cluster_resp['id'] = cluster.id
                resp = {"status": "OK",
                        "cluster": cluster_resp}

        logging.info('get cluster result is %s', cluster_resp)
        return util.make_json_response(200, resp)
Beispiel #10
0
    def get(self, cluster_id, resource=None):
        """
        Lists details of the specified cluster if resource is not specified.
        Otherwise, lists details of the resource of this cluster

        :param cluster_id: the unique identifier of the cluster
        :param resource: the resource name(security, networking, partition)
        """
        cluster_resp = {}
        resp = {}
        with database.session() as session:
            cluster = session.query(ModelCluster)\
                             .filter_by(id=cluster_id)\
                             .first()
            logging.debug('cluster is %s', cluster)
            if not cluster:
                error_msg = 'Cannot found the cluster with id=%s' % cluster_id
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))

            if resource:
                # List resource details
                if resource == self.SECURITY:
                    cluster_resp = cluster.security
                elif resource == self.NETWORKING:
                    cluster_resp = cluster.networking
                elif resource == self.PARTITION:
                    cluster_resp = cluster.partition
                else:
                    error_msg = "Invalid resource name '%s'!" % resource
                    return errors.handle_invalid_usage(
                        errors.UserInvalidUsage(error_msg))
                resp = {"status": "OK", resource: cluster_resp}

            else:
                cluster_resp['clusterName'] = cluster.name
                cluster_resp['link'] = {
                    'rel': 'self',
                    'href': '/'.join((self.ENDPOINT, str(cluster.id)))
                }
                cluster_resp['id'] = cluster.id
                resp = {"status": "OK", "cluster": cluster_resp}

        logging.info('get cluster result is %s', cluster_resp)
        return util.make_json_response(200, resp)
Beispiel #11
0
def execute_cluster_action(cluster_id):
    """
    Execute a specific action to the cluster:
    addHosts: add excepted hosts to the cluster
    removeHosts: remove expected hosts from the cluster
    replaceAllHosts: remove all existing hosts in cluster and add new hosts
    deploy: start to deploy

    :param cluster_id: string of cluster id
    """
    def _add_hosts(cluster_id, hosts):
        """Add cluster host(s) to the cluster by cluster_id"""

        cluseter_hosts = []
        available_machines = []
        failed_machines = []
        with database.session() as session:
            failed_machines = []
            for host in hosts:
                # Check if machine exists
                machine = session.query(ModelMachine).filter_by(id=host)\
                                                     .first()
                if not machine:
                    error_msg = "Machine id=%s does not exist!" % host
                    return errors.handle_not_exist(
                        errors.ObjectDoesNotExist(error_msg)
                        )
                clusterhost = session.query(ModelClusterHost)\
                                     .filter_by(machine_id=host)\
                                     .first()
                if clusterhost:
                    # Machine is already used
                    failed_machines.append(clusterhost.machine_id)
                    continue
                # Add the available machine to available_machines list
                available_machines.append(machine)

            if failed_machines:
                value = {
                    'failedMachines': failed_machines
                }
                error_msg = "Conflict!"
                return errors.handle_duplicate_object(
                    errors.ObjectDuplicateError(error_msg), value
                    )
            for machine, host in zip(available_machines, hosts):
                host = ModelClusterHost(cluster_id=cluster_id,
                                        machine_id=machine.id)
                session.add(host)
                session.flush()
                cluster_res = {}
                cluster_res['id'] = host.id
                cluster_res['machine_id'] = machine.id
                cluseter_hosts.append(cluster_res)

        logging.info('cluster_hosts result is %s', cluseter_hosts)
        return util.make_json_response(
            200, {
                "status": "OK",
                "clusterHosts": cluseter_hosts
                }
            )

    def _remove_hosts(cluster_id, hosts):
        """Remove existing cluster host from the cluster"""

        removed_hosts = []
        with database.session() as session:
            failed_hosts = []
            for host_id in hosts:
                host = session.query(ModelClusterHost).filter_by(id=host_id)\
                                                      .first()

                if not host:
                    failed_hosts.append(host)
                    continue

                host_res = {
                    "id": host_id,
                    "machine_id": host.machine_id
                }
                removed_hosts.append(host_res)

            if failed_hosts:
                error_msg = 'Cluster hosts do not exist!'
                value = {
                    "failedHosts": failed_hosts
                }
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg), value
                    )

            filter_clause = []
            for host_id in hosts:
                filter_clause.append('id=%s' % host_id)

            # Delete the requested hosts from database
            session.query(ModelClusterHost).filter(or_(*filter_clause))\
                   .delete(synchronize_session='fetch')

        return util.make_json_response(
            200, {
                "status": "OK",
                "clusterHosts": removed_hosts
                }
            )

    def _replace_all_hosts(cluster_id, hosts):
        """Remove all existing hosts from the cluster and add new ones"""

        with database.session() as session:
            # Delete all existing hosts of the cluster
            session.query(ModelClusterHost)\
                   .filter_by(cluster_id=cluster_id).delete()
            session.flush()
        return _add_hosts(cluster_id, hosts)

    def _deploy(cluster_id):
        """Deploy the cluster"""

        deploy_hosts_urls = []
        with database.session() as session:
            cluster_hosts_ids = session.query(ModelClusterHost.id)\
                                       .filter_by(cluster_id=cluster_id).all()
            if not cluster_hosts_ids:
                # No host belongs to this cluster
                error_msg = ('Cannot find any host in cluster id=%s' %
                             cluster_id)
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))

            for host_id in cluster_hosts_ids:
                progress_url = '/cluster_hosts/%s/progress' % str(host_id)
                deploy_hosts_urls.append(progress_url)

            # Lock cluster hosts and its cluster
            session.query(ModelClusterHost).filter_by(cluster_id=cluster_id)\
                                           .update({'mutable': False})
            session.query(ModelCluster).filter_by(id=cluster_id)\
                                       .update({'mutable': False})

        celery.send_task("compass.tasks.trigger_install", (cluster_id,))
        return util.make_json_response(
            202, {"status": "OK",
                  "deployment": deploy_hosts_urls})

    request_data = None
    with database.session() as session:
        cluster = session.query(ModelCluster).filter_by(id=cluster_id).first()
        if not cluster:
            error_msg = 'Cluster id=%s does not exist!'
            return errors.handle_not_exist(
                errors.ObjectDoesNotExist(error_msg)
                )
        if not cluster.mutable:
            # The cluster cannot be deploy again
            error_msg = "The cluster id=%s cannot deploy again!" % cluster_id
            return errors.handle_invalid_usage(
                errors.UserInvalidUsage(error_msg))

    request_data = json.loads(request.data)
    action = request_data.keys()[0]
    value = request_data.get(action)

    if 'addHosts' in request_data:
        return _add_hosts(cluster_id, value)

    elif 'removeHosts' in request_data:
        return _remove_hosts(cluster_id, value)

    elif 'deploy' in request_data:
        return _deploy(cluster_id)

    elif 'replaceAllHosts' in request_data:
        return _replace_all_hosts(cluster_id, value)
    else:
        return errors.handle_invalid_usage(
            errors.UserInvalidUsage('%s action is not support!' % action)
            )
Beispiel #12
0
    def get(self):
        """
        List details of all swithes which qualifies the query conditions.
        Filtered by:
            switchIp: switch IP address
            switchIpNetwork: switch IP network
            limit: the number of records excepted to return
        Note: switchIp and swtichIpNetwork cannot be combined to use.
        """
        qkeys = request.args.keys()
        logging.info('SwitchList query strings : %s', qkeys)
        switch_list = []

        with database.session() as session:
            switches = []
            switch_ips = request.args.getlist(self.SWITCHIP)
            switch_ip_network = request.args.get(self.SWITCHIPNETWORK,
                                                 type=str)
            limit = request.args.get(self.LIMIT, 0, type=int)

            if switch_ips and switch_ip_network:
                error_msg = 'switchIp and switchIpNetwork cannot be combined!'
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            if limit < 0:
                error_msg = "limit cannot be less than 1!"
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            if switch_ips:
                for ip_addr in switch_ips:
                    ip_addr = str(ip_addr)
                    if not util.is_valid_ip(ip_addr):
                        error_msg = 'SwitchIp format is incorrect!'
                        return errors.handle_invalid_usage(
                            errors.UserInvalidUsage(error_msg))
                    switch = session.query(ModelSwitch).filter_by(ip=ip_addr)\
                                                       .first()
                    if switch:
                        switches.append(switch)
                        logging.info('[SwitchList][get] ip %s', ip_addr)

            elif switch_ip_network:
                # query all switches which belong to the same network
                if not util.is_valid_ipnetowrk(switch_ip_network):
                    error_msg = 'SwitchIpNetwork format is incorrect!'
                    return errors.handle_invalid_usage(
                        errors.UserInvalidUsage(error_msg))

                def get_queried_ip_prefix(network, prefix):
                    """ Get Ip prefex as pattern used to query switches.
                        Switches' Ip addresses need to match this pattern.
                    """
                    count = int(prefix/8)
                    if count == 0:
                        count = 1
                    return network.rsplit('.', count)[0]+'.'

                from netaddr import IPNetwork, IPAddress

                ip_network = IPNetwork(switch_ip_network)
                ip_filter = get_queried_ip_prefix(str(ip_network.network),
                                                  ip_network.prefixlen)

                logging.info('ip_filter is %s', ip_filter)
                result_set = session.query(ModelSwitch).filter(
                    ModelSwitch.ip.startswith(ip_filter)).all()

                for switch in result_set:
                    ip_addr = str(switch.ip)
                    if IPAddress(ip_addr) in ip_network:
                        switches.append(switch)
                        logging.info('[SwitchList][get] ip %s', ip_addr)

                if limit and len(switches) > limit:
                    switches = switches[:limit]

            elif limit and not switches:
                switches = session.query(ModelSwitch).limit(limit).all()
            else:
                switches = session.query(ModelSwitch).all()

            for switch in switches:
                switch_res = {}
                switch_res['id'] = switch.id
                switch_res['state'] = switch.state
                switch_res['link'] = {
                    'rel': 'self',
                    'href': '/'.join((self.ENDPOINT, str(switch.id)))}
                switch_list.append(switch_res)
        logging.info('get switch list: %s', switch_list)

        return util.make_json_response(
            200, {"status": 'OK',
                  "switches": switch_list})
Beispiel #13
0
def execute_cluster_action(cluster_id):
    """Execute the specified  action to the cluster.

    :param cluster_id: the unique identifier of the cluster
    :param addHosts: the action of adding excepted hosts to the cluster
    :param removeHosts: the action of removing expected hosts from the cluster
    :param replaceAllHosts: the action of removing all existing hosts in
                            cluster and add new hosts
    :param deploy: the action of starting to deploy
    """
    def _add_hosts(cluster_id, hosts):
        """Add cluster host(s) to the cluster by cluster_id"""

        cluseter_hosts = []
        available_machines = []
        failed_machines = []
        with database.session() as session:
            failed_machines = []
            for host in hosts:
                # Check if machine exists
                machine = session.query(ModelMachine).filter_by(id=host)\
                                                     .first()
                if not machine:
                    error_msg = "Machine id=%s does not exist!" % host
                    return errors.handle_not_exist(
                        errors.ObjectDoesNotExist(error_msg))
                clusterhost = session.query(ModelClusterHost)\
                                     .filter_by(machine_id=host)\
                                     .first()
                if clusterhost:
                    # Machine is already used
                    failed_machines.append(clusterhost.machine_id)
                    continue
                # Add the available machine to available_machines list
                available_machines.append(machine)

            if failed_machines:
                value = {'failedMachines': failed_machines}
                error_msg = "Conflict!"
                return errors.handle_duplicate_object(
                    errors.ObjectDuplicateError(error_msg), value)
            for machine, host in zip(available_machines, hosts):
                host = ModelClusterHost(cluster_id=cluster_id,
                                        machine_id=machine.id)
                session.add(host)
                session.flush()
                cluster_res = {}
                cluster_res['id'] = host.id
                cluster_res['machine_id'] = machine.id
                cluseter_hosts.append(cluster_res)

        logging.info('cluster_hosts result is %s', cluseter_hosts)
        return util.make_json_response(200, {
            "status": "OK",
            "cluster_hosts": cluseter_hosts
        })

    def _remove_hosts(cluster_id, hosts):
        """Remove existing cluster host from the cluster"""

        removed_hosts = []
        with database.session() as session:
            failed_hosts = []
            for host_id in hosts:
                host = session.query(ModelClusterHost).filter_by(id=host_id)\
                                                      .first()

                if not host:
                    failed_hosts.append(host)
                    continue

                host_res = {"id": host_id, "machine_id": host.machine_id}
                removed_hosts.append(host_res)

            if failed_hosts:
                error_msg = 'Cluster hosts do not exist!'
                value = {"failedHosts": failed_hosts}
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg), value)

            filter_clause = []
            for host_id in hosts:
                filter_clause.append('id=%s' % host_id)

            # Delete the requested hosts from database
            session.query(ModelClusterHost).filter(or_(*filter_clause))\
                   .delete(synchronize_session='fetch')

        return util.make_json_response(200, {
            "status": "OK",
            "cluster_hosts": removed_hosts
        })

    def _replace_all_hosts(cluster_id, hosts):
        """Remove all existing hosts from the cluster and add new ones"""

        with database.session() as session:
            # Delete all existing hosts of the cluster
            session.query(ModelClusterHost)\
                   .filter_by(cluster_id=cluster_id).delete()
            session.flush()
        return _add_hosts(cluster_id, hosts)

    def _deploy(cluster_id):
        """Deploy the cluster"""

        deploy_hosts_urls = []
        with database.session() as session:
            cluster_hosts_ids = session.query(ModelClusterHost.id)\
                                       .filter_by(cluster_id=cluster_id).all()
            if not cluster_hosts_ids:
                # No host belongs to this cluster
                error_msg = ('Cannot find any host in cluster id=%s' %
                             cluster_id)
                return errors.handle_not_exist(
                    errors.ObjectDoesNotExist(error_msg))

            for elm in cluster_hosts_ids:
                host_id = str(elm[0])
                progress_url = '/cluster_hosts/%s/progress' % host_id
                deploy_hosts_urls.append(progress_url)

            # Lock cluster hosts and its cluster
            session.query(ModelClusterHost).filter_by(cluster_id=cluster_id)\
                                           .update({'mutable': False})
            session.query(ModelCluster).filter_by(id=cluster_id)\
                                       .update({'mutable': False})

        celery.send_task("compass.tasks.trigger_install", (cluster_id, ))
        return util.make_json_response(202, {
            "status": "OK",
            "deployment": deploy_hosts_urls
        })

    request_data = None
    with database.session() as session:
        cluster = session.query(ModelCluster).filter_by(id=cluster_id).first()
        if not cluster:
            error_msg = 'Cluster id=%s does not exist!'
            return errors.handle_not_exist(
                errors.ObjectDoesNotExist(error_msg))
        if not cluster.mutable:
            # The cluster cannot be deploy again
            error_msg = "The cluster id=%s cannot deploy again!" % cluster_id
            return errors.handle_invalid_usage(
                errors.UserInvalidUsage(error_msg))

    request_data = json.loads(request.data)
    action = request_data.keys()[0]
    value = request_data.get(action)

    if 'addHosts' in request_data:
        return _add_hosts(cluster_id, value)

    elif 'removeHosts' in request_data:
        return _remove_hosts(cluster_id, value)

    elif 'deploy' in request_data:
        return _deploy(cluster_id)

    elif 'replaceAllHosts' in request_data:
        return _replace_all_hosts(cluster_id, value)
    else:
        return errors.handle_invalid_usage(
            errors.UserInvalidUsage('%s action is not support!' % action))
Beispiel #14
0
    def get(self):
        """
        List details of all switches, optionally filtered by some conditions.
        Note: switchIp and swtichIpNetwork cannot be combined to use.

        :param switchIp: switch IP address
        :param switchIpNetwork: switch IP network
        :param limit: the number of records excepted to return
        """
        qkeys = request.args.keys()
        logging.info('SwitchList query strings : %s', qkeys)
        switch_list = []

        with database.session() as session:
            switches = []
            switch_ips = request.args.getlist(self.SWITCHIP)
            switch_ip_network = request.args.get(self.SWITCHIPNETWORK,
                                                 type=str)
            limit = request.args.get(self.LIMIT, 0, type=int)

            if switch_ips and switch_ip_network:
                error_msg = 'switchIp and switchIpNetwork cannot be combined!'
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            if limit < 0:
                error_msg = "limit cannot be less than 1!"
                return errors.handle_invalid_usage(
                    errors.UserInvalidUsage(error_msg))

            if switch_ips:
                for ip_addr in switch_ips:
                    ip_addr = str(ip_addr)
                    if not util.is_valid_ip(ip_addr):
                        error_msg = 'SwitchIp format is incorrect!'
                        return errors.handle_invalid_usage(
                            errors.UserInvalidUsage(error_msg))
                    switch = session.query(ModelSwitch).filter_by(ip=ip_addr)\
                                                       .first()
                    if switch:
                        switches.append(switch)
                        logging.info('[SwitchList][get] ip %s', ip_addr)

            elif switch_ip_network:
                # query all switches which belong to the same network
                if not util.is_valid_ipnetowrk(switch_ip_network):
                    error_msg = 'SwitchIpNetwork format is incorrect!'
                    return errors.handle_invalid_usage(
                        errors.UserInvalidUsage(error_msg))

                def get_queried_ip_prefix(network, prefix):
                    """ Get Ip prefex as pattern used to query switches.
                        Switches' Ip addresses need to match this pattern.
                    """
                    count = int(prefix / 8)
                    if count == 0:
                        count = 1
                    return network.rsplit('.', count)[0] + '.'

                from netaddr import IPNetwork, IPAddress

                ip_network = IPNetwork(switch_ip_network)
                ip_filter = get_queried_ip_prefix(str(ip_network.network),
                                                  ip_network.prefixlen)

                logging.info('ip_filter is %s', ip_filter)
                result_set = session.query(ModelSwitch).filter(
                    ModelSwitch.ip.startswith(ip_filter)).all()

                for switch in result_set:
                    ip_addr = str(switch.ip)
                    if IPAddress(ip_addr) in ip_network:
                        switches.append(switch)
                        logging.info('[SwitchList][get] ip %s', ip_addr)

                if limit and len(switches) > limit:
                    switches = switches[:limit]

            elif limit and not switches:
                switches = session.query(ModelSwitch).limit(limit).all()
            else:
                switches = session.query(ModelSwitch).all()

            for switch in switches:
                switch_res = {}
                switch_res['id'] = switch.id
                switch_res['ip'] = switch.ip
                switch_res['state'] = switch.state
                switch_res['link'] = {
                    'rel': 'self',
                    'href': '/'.join((self.ENDPOINT, str(switch.id)))
                }
                switch_list.append(switch_res)
        logging.info('get switch list: %s', switch_list)

        return util.make_json_response(200, {
            "status": 'OK',
            "switches": switch_list
        })