From 9c54d458037a7fb3c850aec5ce61646738d7c2e7 Mon Sep 17 00:00:00 2001 From: "grace.yu" Date: Fri, 31 Jan 2014 15:06:21 -0800 Subject: [PATCH] Update API Change-Id: I9fa5660321cae7312f63ce359d67d9f9276e4d72 --- compass/api/api.py | 12 ++++ compass/api/util.py | 1 + compass/apiclient/restful.py | 132 ++++++++++++++++++++-------------- compass/tests/api/test_api.py | 34 +++++++-- 4 files changed, 119 insertions(+), 60 deletions(-) diff --git a/compass/api/api.py b/compass/api/api.py index 9934fbdb..4f9a502a 100644 --- a/compass/api/api.py +++ b/compass/api/api.py @@ -285,6 +285,7 @@ class MachineList(Resource): ENDPOINT = "/machines" SWITCHID = 'switchId' + MAC = 'mac' VLANID = 'vladId' PORT = 'port' LIMIT = 'limit' @@ -296,11 +297,13 @@ class MachineList(Resource): be filtered. :param switchId: the unique identifier of the switch + :param mac: the MAC address :param vladId: the vlan ID :param port: the port number :param limit: the number of records expected to return """ switch_id = request.args.get(self.SWITCHID, type=int) + mac = request.args.get(self.MAC, None, type=str) vlan = request.args.get(self.VLANID, type=int) port = request.args.get(self.PORT, None) limit = request.args.get(self.LIMIT, 0, type=int) @@ -311,6 +314,9 @@ class MachineList(Resource): if switch_id: filter_clause.append('switch_id=%d' % switch_id) + if mac: + filter_clause.append('mac=%s' % mac) + if vlan: filter_clause.append('vlan=%d' % vlan) @@ -488,6 +494,12 @@ class Cluster(Resource): return errors.handle_duplicate_object( errors.ObjectDuplicateError(error_msg)) + adapter = session.query(Adapter).filter_by(id=adapter_id).first() + if not adapter: + error_msg = "No adapter id=%s can be found!" + return errors.handle_not_exist( + errors.ObjectDoesNotExist(error_msg)) + # Create a new cluster in database cluster = ModelCluster(name=cluster_name, adapter_id=adapter_id) session.add(cluster) diff --git a/compass/api/util.py b/compass/api/util.py index 150c4437..ed3f7d18 100644 --- a/compass/api/util.py +++ b/compass/api/util.py @@ -260,6 +260,7 @@ def valid_host_config(config): from api import errors valid_format = {"/networking/interfaces/management/ip": "is_valid_ip", + "/networking/interfaces/tenant/ip": "is_valid_ip", "/networking/global/gateway": "is_valid_gateway", "/networking/global/nameserver": "", "/networking/global/search_path": "", diff --git a/compass/apiclient/restful.py b/compass/apiclient/restful.py index 29f9d28a..539c64fb 100644 --- a/compass/apiclient/restful.py +++ b/compass/apiclient/restful.py @@ -129,7 +129,7 @@ class Client(object): return self._get('/api/switches/%s' % switch_id) def add_switch(self, switch_ip, version=None, community=None, - username=None, password=None): + username=None, password=None, raw_data=None): """Create a switch with specified details. .. note:: @@ -149,26 +149,30 @@ class Client(object): :type password: str. """ data = {} - data['switch'] = {} - data['switch']['ip'] = switch_ip - data['switch']['credential'] = {} - if version: - data['switch']['credential']['version' ] = version + if raw_data: + data = raw_data + else: + data['switch'] = {} + data['switch']['ip'] = switch_ip + data['switch']['credential'] = {} + if version: + data['switch']['credential']['version'] = version - if community: - data['switch']['credential']['community'] = community + if community: + data['switch']['credential']['community'] = community - if username: - data['switch']['credential']['username'] = username + if username: + data['switch']['credential']['username'] = username - if password: - data['switch']['credential']['password'] = password + if password: + data['switch']['credential']['password'] = password return self._post('/api/switches', data=data) def update_switch(self, switch_id, ip_addr=None, version=None, community=None, - username=None, password=None): + username=None, password=None, + raw_data=None): """Updates a switch with specified details. .. note:: @@ -189,22 +193,25 @@ class Client(object): :param password: password when using SSH to poll switch. """ data = {} - data['switch'] = {} - if ip_addr: - data['switch']['ip'] = ip_addr + if raw_data: + data = raw_data + else: + data['switch'] = {} + if ip_addr: + data['switch']['ip'] = ip_addr - data['switch']['credential'] = {} - if version: - data['switch']['credential']['version' ] = version + data['switch']['credential'] = {} + if version: + data['switch']['credential']['version'] = version - if community: - data['switch']['credential']['community'] = community + if community: + data['switch']['credential']['community'] = community - if username: - data['switch']['credential']['username'] = username + if username: + data['switch']['credential']['username'] = username - if password: - data['switch']['credential']['password'] = password + if password: + data['switch']['credential']['password'] = password return self._put('/api/switches/%s' % switch_id, data=data) @@ -266,7 +273,7 @@ class Client(object): """ return self._get('/api/clusters/%s' % cluster_id) - def add_cluster(self, cluster_name, adapter_id): + def add_cluster(self, cluster_name, adapter_id, raw_data=None): """Creates a cluster by specified name and given adapter id. :param cluster_name: cluster name. @@ -275,12 +282,15 @@ class Client(object): :type adapter_id: int. """ data = {} - data['cluster'] = {} - data['cluster']['name'] = cluster_name - data['cluster']['adapter_id'] = adapter_id + if raw_data: + data = raw_data + else: + data['cluster'] = {} + data['cluster']['name'] = cluster_name + data['cluster']['adapter_id'] = adapter_id return self._post('/api/clusters', data=data) - def add_hosts(self, cluster_id, machine_ids): + def add_hosts(self, cluster_id, machine_ids, raw_data=None): """add the specified machine(s) as the host(s) to the cluster. :param cluster_id: cluster id. @@ -289,10 +299,13 @@ class Client(object): :type machine_ids: list of int, each is the id of one machine. """ data = {} - data['addHosts'] = machine_ids + if raw_data: + data = raw_data + else: + data['addHosts'] = machine_ids return self._post('/api/clusters/%s/action' % cluster_id, data=data) - def remove_hosts(self, cluster_id, host_ids): + def remove_hosts(self, cluster_id, host_ids, raw_data=None): """remove the specified host(s) from the cluster. :param cluster_id: cluster id. @@ -301,10 +314,13 @@ class Client(object): :type host_ids: list of int, each is the id of one host. """ data = {} - data['removeHosts'] = host_ids + if raw_data: + data = raw_data + else: + data['removeHosts'] = host_ids return self._post('/api/clusters/%s/action' % cluster_id, data=data) - def replace_hosts(self, cluster_id, machine_ids): + def replace_hosts(self, cluster_id, machine_ids, raw_data=None): """replace the cluster hosts with the specified machine(s). :param cluster_id: int, The unique identifier of the cluster. @@ -313,17 +329,23 @@ class Client(object): :type machine_ids: list of int, each is the id of one machine. """ data = {} - data['replaceAllHosts'] = machine_ids + if raw_data: + data = raw_data + else: + data['replaceAllHosts'] = machine_ids return self._post('/api/clusters/%s/action' % cluster_id, data=data) - def deploy_hosts(self, cluster_id): + def deploy_hosts(self, cluster_id, raw_data=None): """Deploy the cluster. :param cluster_id: The unique identifier of the cluster :type cluster_id: int. """ data = {} - data['deploy'] = {} + if raw_data: + data = raw_data + else: + data['deploy'] = [] return self._post('/api/clusters/%s/action' % cluster_id, data=data) @classmethod @@ -481,7 +503,7 @@ class Client(object): return self._get('/api/clusterhosts/%s/config' % host_id) def update_host_config(self, host_id, hostname=None, - roles=None, **kwargs): + roles=None, raw_data=None, **kwargs): """Updates config for the host. :param host_id: host id. @@ -518,25 +540,29 @@ class Client(object): :type roles: list of str. """ data = {} - if hostname: - data['hostname'] = hostname + if raw_data: + data = raw_data + else: + if hostname: + data['hostname'] = hostname - sub_kwargs = {} - for key, value in kwargs.items(): - key_name, key_value = key.split('_', 1) - sub_kwargs.setdefault(key_name, {})[key_value] = value + sub_kwargs = {} + for key, value in kwargs.items(): + key_name, key_value = key.split('_', 1) + sub_kwargs.setdefault(key_name, {})[key_value] = value - if 'security' in sub_kwargs: - data['security'] = self.parse_security(sub_kwargs['security']) + if 'security' in sub_kwargs: + data['security'] = self.parse_security(sub_kwargs['security']) - if 'networking' in sub_kwargs: - data['networking'] = self.parse_networking( - sub_kwargs['networking']) - if 'partition' in sub_kwargs: - data['partition'] = self.parse_partition(sub_kwargs['partition']) + if 'networking' in sub_kwargs: + data['networking'] = self.parse_networking( + sub_kwargs['networking']) + if 'partition' in sub_kwargs: + data['partition'] = self.parse_partition( + sub_kwargs['partition']) - if roles: - data['roles'] = roles + if roles: + data['roles'] = roles return self._put('/api/clusterhosts/%s/config' % host_id, data) diff --git a/compass/tests/api/test_api.py b/compass/tests/api/test_api.py index 73e23f4f..2dfb8a67 100644 --- a/compass/tests/api/test_api.py +++ b/compass/tests/api/test_api.py @@ -260,7 +260,8 @@ class TestSwtichMachineAPI(ApiTestCase): {'url': '/machines?switchId=1', 'expected': 8}, # TODO: #{'url': '/machines?switchId=1&port=6', 'expected': 1}, - {'url': '/machines?switchId=4', 'expected': 0}] + {'url': '/machines?switchId=4', 'expected': 0}, + {'url': "/machines?mac='00:27:88:0c:01'", 'expected': 1}] for test in testList: url = test['url'] @@ -355,21 +356,29 @@ class TestClusterAPI(ApiTestCase): # Create a cluster def test_post_cluster(self): - # a. Post a new cluster + # a. Post a new cluster but no adapter exists cluster_req = {'cluster': {'name': 'cluster_02', 'adapter_id': 1}} url = '/clusters' rv = self.app.post(url, data=json.dumps(cluster_req)) data = json.loads(rv.get_data()) - self.assertEqual(rv.status_code, 200) + self.assertEqual(rv.status_code, 404) + + #b. Post a cluster sucessfully + with database.session() as session: + adapter = Adapter(name='Centos_openstack', os='Centos', + target_system='openstack') + session.add(adapter) + rv = self.app.post(url, data=json.dumps(cluster_req)) + data = json.loads(rv.get_data()) self.assertEqual(data['cluster']['id'], 2) self.assertEqual(data['cluster']['name'], 'cluster_02') - #b. Post an existing cluster, return 409 + #c. Post an existing cluster, return 409 rv = self.app.post(url, data=json.dumps(cluster_req)) self.assertEqual(rv.status_code, 409) - #c. Post a new cluster without providing a name + #d. Post a new cluster without providing a name cluster_req['cluster']['name'] = '' rv = self.app.post(url, data=json.dumps(cluster_req)) data = json.loads(rv.get_data()) @@ -969,6 +978,9 @@ class TestAPIWorkFlow(ApiTestCase): "interfaces": { "management": { "ip": "" + }, + "tenant": { + "ip": "" } } }, @@ -997,6 +1009,10 @@ class TestAPIWorkFlow(ApiTestCase): session.add_all(machines) + adapter = Adapter(name='Centos_openstack', os='Centos', + target_system='openstack') + session.add(adapter) + def tearDown(self): super(TestAPIWorkFlow, self).tearDown() @@ -1020,6 +1036,7 @@ class TestAPIWorkFlow(ApiTestCase): machines = json.loads(rv.get_data())['machines'] # Create a Cluster and get cluster id from response + # In this example, adapter_id will be 1 by default. url = '/clusters' data = { "cluster": { @@ -1068,9 +1085,12 @@ class TestAPIWorkFlow(ApiTestCase): ] names = ["host_01", "host_02", "host_03"] mgmt_ips = ["10.120.8.100", "10.120.8.101", "10.120.8.102"] - for config, name, ip in zip(hosts_configs, names, mgmt_ips): + tenant_ips = ["12.120.8.100", "12.120.8.101", "12.120.8.102"] + for config, name, mgmt_ip, tenant_ip in zip(hosts_configs, names, + mgmt_ips, tenant_ips): config["hostname"] = name - config["networking"]["interfaces"]["management"]["ip"] = ip + config["networking"]["interfaces"]["management"]["ip"] = mgmt_ip + config["networking"]["interfaces"]["tenant"]["ip"] = tenant_ip for config, host_info in zip(hosts_configs, hosts_info): host_id = host_info["id"]