From 0ad3c180647ad116e3874ea38085fb10829af2af Mon Sep 17 00:00:00 2001 From: liuqi <469227928@qq.com> Date: Mon, 20 Dec 2021 20:00:10 +0800 Subject: [PATCH] complement code --- libs/cloud/HWCloud/ecs_servers.py | 303 ++++++++++++++++++++++++++---- 1 file changed, 267 insertions(+), 36 deletions(-) diff --git a/libs/cloud/HWCloud/ecs_servers.py b/libs/cloud/HWCloud/ecs_servers.py index 8658c82..3b4e3bd 100644 --- a/libs/cloud/HWCloud/ecs_servers.py +++ b/libs/cloud/HWCloud/ecs_servers.py @@ -5,9 +5,20 @@ import requests import time import yaml from libs.log.logger import log_check +from requests.adapters import HTTPAdapter +from urllib3.util.retry import Retry + +retries = Retry(total=3, backoff_factor=0.1) +session = requests.Session() +session.mount('https://', HTTPAdapter(max_retries=retries)) +timeout = 5 class ECSServers(object): + """ + wrapped HUAWEI CLOUD ECS Servers APIs + """ + def __init__(self, conf_path): super(ECSServers, self).__init__() self.conf_path = conf_path @@ -20,37 +31,21 @@ class ECSServers(object): except FileNotFoundError as e2: log_check(e2) if info: - region = info.get('region') - project_id = info.get('projectId') - headers = self.get_auth_header(region) - name_prefix = info.get('name_prefix') - vpcId = info.get('vpcId') - subnetId = info.get('subnetId') - security_group_id = info.get('security_group_id') - volumetype = info.get('volumetype') - waiting_time = info.get('waiting_time') - query_times = info.get('query_times') - server_boot_time = info.get('server_boot_time') - max_servers_number = info.get('max_servers_number') - max_list_number = info.get('max_list_number') - flavorMapping = info.get('flavorMapping') - archMapping = info.get('archMapping') - ECSServers.info = info - ECSServers.region = region - ECSServers.project_id = project_id - ECSServers.headers = headers - ECSServers.name_prefix = name_prefix - ECSServers.vpcId = vpcId - ECSServers.subnetId = subnetId - ECSServers.security_group_id = security_group_id - ECSServers.volumetype = volumetype - ECSServers.waiting_time = waiting_time - ECSServers.query_times = query_times - ECSServers.server_boot_time = server_boot_time - ECSServers.max_servers_number = max_servers_number - ECSServers.max_list_number = max_list_number - ECSServers.flavorMapping = flavorMapping - ECSServers.archMapping = archMapping + self.region = info.get('region') + self.project_id = info.get('projectId') + self.headers = self.get_auth_header(self.region) + self.name_prefix = info.get('name_prefix') + self.vpcId = info.get('vpcId') + self.subnetId = info.get('subnetId') + self.security_group_id = info.get('security_group_id') + self.volumetype = info.get('volumetype') + self.waiting_time = info.get('waiting_time') + self.query_times = info.get('query_times') + self.server_boot_time = info.get('server_boot_time') + self.max_servers_number = info.get('max_servers_number') + self.max_list_number = info.get('max_list_number') + self.flavorMapping = info.get('flavorMapping') + self.archMapping = info.get('archMapping') @staticmethod def get_auth_header(project_region): @@ -83,7 +78,7 @@ class ECSServers(object): } } } - response = requests.post(url, data=json.dumps(data)) + response = session.post(url, data=json.dumps(data), timeout=timeout) try: token = response.headers["X-Subject-Token"] header = {'X-Auth-Token': token} @@ -93,6 +88,14 @@ class ECSServers(object): log_check.error('Get authorized token: Fail to get auth token.') def validate_create_fields(self, arch, flavor_level, admin_pass, count): + """ + Validation of the created fields + :param arch: architecture of servers + :param flavor_level: specifies the flavor level of servers + :param admin_pass: password for root + :param count: numbers of servers + :return: + """ if arch not in self.flavorMapping.keys(): result = {'code': 400, 'error': 'Unmatched architecture name.'} log_check.error('Create servers: {}'.format(result)) @@ -110,7 +113,7 @@ class ECSServers(object): log_check.error('Create servers: {}'.format(result)) return result max_number_can_create = self.get_max_number_can_create() - if not max_number_can_create: + if max_number_can_create == 0: result = {'code': 400, 'error': 'Cannot get maximum number of servers that can be created.'} log_check.error('Create servers: {}'.format(result)) return result @@ -122,6 +125,19 @@ class ECSServers(object): @staticmethod def get_create_data(admin_pass, count, flavorRef, imageRef, name, vpcid, subnet_id, security_group_id, volumetype): + """ + Data for creating servers + :param admin_pass: password for root + :param count: numbers of servers + :param flavorRef: name of flavor + :param imageRef: UUID of image + :param name: server name + :param vpcid: UUID of VPC + :param subnet_id: UUID of subnet + :param security_group_id: UUID of security group + :param volumetype: + :return: + """ data = { 'server': { 'adminPass': admin_pass, @@ -159,12 +175,10 @@ class ECSServers(object): result = self.validate_create_fields(arch, flavor_level, admin_pass, count) if result: return result - url = 'https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers'.format(self.region, self.project_id) try: flavorRef = self.flavorMapping.get(arch).get(flavor_level) imageRef = self.flavorMapping.get(arch).get('imageRef') - print(flavorRef, imageRef) except AttributeError as e: log_check.error(e) result = {'code': 400, 'error': e} @@ -179,7 +193,7 @@ class ECSServers(object): server_boot_time = self.server_boot_time data = self.get_create_data(admin_pass, count, flavorRef, imageRef, name, vpcid, subnet_id, security_group_id, volumetype) - response = requests.post(url, headers=self.headers, data=json.dumps(data)) + response = session.post(url, headers=self.headers, data=json.dumps(data), timeout=timeout) if response.status_code == 200: serverIds = response.json()['serverIds'] while query_times > 0: @@ -198,5 +212,222 @@ class ECSServers(object): log_check.error('Create servers: {}'.format(result)) return result + def get_format_server(self, server, status='ACTIVE'): + """ + Get formatted data of a server + :param server: a dict of server data + :param status: running status of the server + :return: a dict contained id, name, ip, status, flavor and arch + """ + format_server = { + 'id': server.get('id'), + 'name': server.get('name'), + 'ip': server.get('addresses').get(list(server.get('addresses').keys())[0])[0].get('addr') if server.get( + 'addresses') else '', + 'status': status, + 'flavor': { + 'vcpus': server.get('flavor').get('vcpus'), + 'ram': server.get('flavor').get('ram') + }, + 'arch': self.get_arch(server.get('flavor').get('name')) + } + return format_server + + def list_servers(self): + """ + List all active servers about obs + :return: a list of all server details + """ + url = 'https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers/detail?limit={}&status=ACTIVE&name=obs'.format( + self.region, self.project_id, self.max_list_number) + response = session.get(url, headers=self.headers, timeout=timeout) + if response.status_code == 200: + servers = [] + for server in response.json().get('servers'): + if server.get('addresses'): + format_server = self.get_format_server(server) + servers.append(format_server) + result = {'code': 200, 'servers': servers} + else: + result = {'code': 400, 'error': response.json()} + return result + + def get_server(self, server_ip): + """ + Get a server detail by server_ip + :param server_ip: IP address + :return: server detail + """ + server_id = self.get_server_id(server_ip) + if not server_id: + log_check.error('Get server: IP {} does not exists.'.format(server_ip)) + return {'code': 400, 'error': 'Not exist'} + url = ' https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers/{}'.format(self.region, self.project_id, server_id) + response = session.get(url, headers=self.headers, timeout=timeout) + if response.status_code == 200: + server = response.json().get('server') + status = server.get('status') + if status == 'BUILD': + status = 'BUILDING' + elif status not in ['BUILDING', 'ACTIVE', 'DELETED']: + status = 'OTHER' + format_server = self.get_format_server(server, status) + result = {'code': 200, 'server': format_server} + log_check.info('Get server: {}'.format(result)) + else: + result = {'code': 400, 'error': response.json()} + log_check.error('Get server: {}'.format(result)) + return result + + def delete_servers(self, serverIps): + """ + Delete servers + :param serverIps: a list of IP address + :return: + """ + serverIds = self.get_server_ids(serverIps) + url = 'https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers/delete'.format(self.region, self.project_id) + servers = [{'id': server_id} for server_id in serverIds] + data = { + 'delete_publicip': True, + 'delete_volume': True, + 'servers': servers + } + response = session.post(url, headers=self.headers, data=json.dumps(data), timeout=timeout) + if response.status_code == 200: + result = {'code': 200, 'message': 'Delete successfully'} + log_check.info('Delete servers: {}'.format(serverIps)) + else: + result = {'code': 400, 'error': response.json()} + log_check.error('Delete servers: {}'.format(result)) + return result + + def get_arch(self, flavor_name): + """ + Get architecture by flavor_name + :param flavor_name: name of flavor + :return: architecture of the server + """ + for arch in self.archMapping: + if flavor_name in self.archMapping.get(arch): + return arch + + def get_server_maps(self): + """ + Get mapping between IP addresses and server_ids + :return: A list of nested dictionaries {ip: server_id} + """ + url = 'https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers/detail?limit={}&status=ACTIVE&name=obs'.format( + self.region, self.project_id, self.max_list_number) + response = session.get(url, headers=self.headers, timeout=timeout) + if response.status_code == 200: + server_maps = [ + {server.get('addresses').get(list(server.get('addresses').keys())[0])[0].get('addr'): server.get('id')} + if server.get('addresses') else {None: server.get('id')} + for server in response.json()['servers']] + return server_maps + else: + return {} + + def get_hostname_maps(self): + """ + Get mapping between IP addresses and hostnames + :return: A list of nested dictionaries {IP: hostname} + """ + url = 'https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers/detail?limit={}&status=ACTIVE&name=obs'.format( + self.region, self.project_id, self.max_list_number) + response = session.get(url, headers=self.headers, timeout=timeout) + if response.status_code == 200: + hostname_maps = [{server.get('addresses').get(list(server.get('addresses').keys())[0])[0].get( + 'addr'): server.get('name')} + if server.get('addresses') else {None: server.get('id')} + for server in response.json()['servers']] + return hostname_maps + else: + return {} + + def get_hostname(self, server_ip): + """ + Get hostname of the server through IP address + :param server_ip: IP address + :return: hostname of the server + """ + servers = self.get_hostname_maps() + for server in servers: + if server.get(server_ip): + hostname = server.get(server_ip) + return hostname + + def get_server_id(self, server_ip): + """ + Get the server_id through IP address + :param server_ip: IP address + :return: server_id + """ + servers = self.get_server_maps() + for server in servers: + if server.get(server_ip): + server_id = server.get(server_ip) + return server_id + + def get_server_ids(self, server_ips): + """ + Get a list of server_id through IP addresses + :param server_ips: list of IP address + :return: list of server_id + """ + servers = self.get_server_maps() + server_ids = [] + for ip in server_ips: + for server in servers: + if server.get(ip): + server_id = server.get(ip) + server_ids.append(server_id) + break + return server_ids + + def get_server_ip(self, server_id: str): + """ + Get IP address through server_id + :param server_id: server_id + :return: IP address + """ + servers = self.get_server_maps() + for server in servers: + if server.get(list(server.keys())[0]) == server_id: + return list(server.keys())[0] + + def get_server_ips(self, server_ids: list): + """ + Get a list of IP addresses through server_ids + :param server_ids: list of server_id + :return: list of IP address + """ + servers = self.get_server_maps() + server_ips = [] + for server_id in server_ids: + for server in servers: + server_ip = list(server.keys())[0] + if server.get(server_ip) == server_id: + server_ips.append(server_ip) + break + return server_ips + + def get_max_number_can_create(self): + """ + Get maximum number of servers can be created + :return: count of remaining servers can be created or None when error occurs + """ + url = 'https://ecs.{}.myhuaweicloud.com/v1/{}/cloudservers/detail'.format(self.region, self.project_id) + response = session.get(url, headers=self.headers, timeout=timeout) + if response.status_code != 200: + result = {'code': 400, 'error': response.json()} + log_check.error('Get max number can create: {}'.format(result)) + return 0 + count = response.json().get('count') + max_servers_number = self.max_servers_number + return max_servers_number - count + ecs_server = ECSServers('/usr/li-wen/libs/conf/ecs_servers.yaml') + -- Gitee