| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760 |
- #! usr/bin/python
- # -*-coding:utf-8 -*-
- # Copyright 2014 Baidu, Inc.
- #
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- # except in compliance with the License. You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software distributed under the
- # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- # either express or implied. See the License for the specific language governing permissions
- # and limitations under the License.
- """
- This module provides a client class for SCS.
- """
- from __future__ import unicode_literals
- import copy
- import json
- import logging
- import uuid
- import http.client
- import baidubce.services.scs.model as model
- from baidubce import utils
- from baidubce.auth import bce_v1_signer
- from baidubce.bce_base_client import BceBaseClient
- from baidubce.bce_client_configuration import BceClientConfiguration
- from baidubce.exception import BceClientError
- from baidubce.exception import BceServerError
- from baidubce.http import bce_http_client
- from baidubce.http import http_headers
- from baidubce.http import http_methods
- from baidubce.services import scs
- from baidubce.utils import required
- _logger = logging.getLogger(__name__)
- def _parse_result(http_response, response):
- if http_response.status / 100 == http.client.CONTINUE / 100:
- raise BceClientError('Can not handle 1xx http status code')
- bse = None
- body = http_response.read()
- if body:
- d = json.loads(body)
- if 'message' in d and 'code' in d and 'requestId' in d:
- r_code = d['code']
- # 1000 means success
- if r_code != '1000':
- bse = BceServerError(d['message'],
- code=d['code'],
- request_id=d['requestId'])
- else:
- response.__dict__.update(
- json.loads(body, object_hook=utils.dict_to_python_object).__dict__)
- http_response.close()
- return True
- elif http_response.status / 100 == http.client.OK / 100:
- response.__dict__.update(
- json.loads(body, object_hook=utils.dict_to_python_object).__dict__)
- http_response.close()
- return True
- elif http_response.status / 100 == http.client.OK / 100:
- return True
- if bse is None:
- bse = BceServerError(http_response.reason, request_id=response.metadata.bce_request_id)
- bse.status_code = http_response.status
- raise bse
- class ScsClient(BceBaseClient):
- """
- Scs sdk client
- """
- def __init__(self, config=None):
- if config is not None:
- self._check_config_type(config)
- BceBaseClient.__init__(self, config)
- @required(config=BceClientConfiguration)
- def _check_config_type(self, config):
- return True
- @required(engine_version=(str), instance_name=(str), cluster_type=(str),
- node_type=(str), shard_num=int, proxy_num=int,
- replication_num=int, store_type=int, vpc_id=(str), subnets=list, port=int, purchase_count=int,
- auto_renew_time_unit=(str), auto_renew_time=int, billing=model.Billing)
- def create_instance(self, engine_version, instance_name, cluster_type, node_type, shard_num, replication_num,
- proxy_num=0, store_type=None, vpc_id=None, subnets=None, port=6379, purchase_count=1,
- auto_renew_time_unit='month', auto_renew_time=None, billing=model.Billing(), config=None):
- """
- Create instance with specific config
- :param engine_version:
- :type engine_version:string or unicode
- :param instance_name: Instance name
- :type name: string or unicode
- :param cluster_type: default/master_slave or cluster
- :type cluster_type: string or unicode
- :param node_type: Node specification
- :type node_type: string or unicode
- :param shard_num: number of shard
- :type shard_num: int
- :param replication_num: number of replication
- :type replication_num: int
- :param store_type: default is 0;High performance memory:0;ssd-native:1
- :type store_type: int
- :param vpc_id: vpc id,use default vpc id if not provide.
- :type vpc_id: str
- :param subnets: list of model.SubnetMap
- :type subnets: list
- :param port: default is 6379
- :type port: int
- :param purchase_count: Number of purchases, default is 1
- :type purchase_count: int
- :param auto_renew_time_unit: Renew monthly or yearly,value in ['month','year]
- :type auto_renew_time_unit: str
- :param auto_renew_time: If billing is Prepay, the automatic renewal time is 1-9
- when auto_renew_time_unit is 'month' and 1-3 when auto_renew_time_unit is 'year'
- :type auto_renew_time: int
- :param billing: default billing is Prepay 1 month
- :type billing: model.Billing
- :param config: None
- :type config: BceClientConfiguration
- :return: Object
- {
- "instance_ids": ["scs-bj-wHoJXL09355"]
- }
- :rtype: baidubce.bce_response.BceResponse
- """
- data = {
- 'billing': billing.__dict__,
- 'instanceName': instance_name,
- 'nodeType': node_type,
- 'port': port,
- 'engineVersion': engine_version,
- 'storeType': store_type,
- 'purchaseCount': purchase_count,
- 'shardNum': shard_num,
- 'proxyNum': proxy_num,
- 'replicationNum': replication_num,
- 'clusterType': cluster_type,
- 'vpcId': vpc_id,
- 'subnets': subnets,
- 'autoRenewTimeUnit': auto_renew_time_unit,
- 'autoRenewTime': auto_renew_time
- }
- return model.CreateInstanceResponse(self._send_request(http_methods.POST, 'instance',
- params={"clientToken": uuid.uuid4()},
- body=json.dumps(data, cls=model.JsonWrapper, indent=4),
- config=config,
- api_version=2))
- @required(engine_version=(str), instance_id=(str),
- node_type=(str), shard_num=int, proxy_num=int, billing=model.Billing)
- def resize_instance(self, instance_id, node_type, shard_num=None, engine_version=None, billing=None, config=None):
- """
- Create instance with specific config
- :param engine_version:
- :type engine_version:string or unicode
- :type name: string or unicode
- :param node_type: Node specification
- :type node_type: string or unicode
- :param instance_id: number of shard
- :type shard_num: int
- :param shard_num: number of proxy node
- :type shard_num: int
- :param billing: default billing is Prepay 1 month
- :type billing: model.Billing
- :param config: None
- :type config: BceClientConfiguration
- """
- response = self.get_instance_detail(instance_id)
- billing = model.Billing(pay_method=response.payment_timing)
- if engine_version is None:
- engine_version = response.engine_version
- if shard_num is None:
- shard_num = response.shard_num
- data = {
- 'billing': billing.__dict__,
- 'nodeType': node_type,
- 'engineVersion': engine_version,
- 'shardNum': shard_num
- }
- key = instance_id + '/resize'
- return model.CreateInstanceResponse(self._send_request(http_methods.PUT, 'instance', key=key,
- body=json.dumps(data), config=config))
- @required(instance_id=(str))
- def delete_instance(self, instance_id, config=None):
- """
- Delete instance
- :param instance_id: The ID of instance
- :type instance_id: string or unicode
- :param config: None
- :type config: BceClientConfiguration
- :return:
- """
- return self._send_request(http_method=http_methods.DELETE, function_name='instance', key=instance_id,
- config=config, api_version=1)
- def list_instances(self, marker=None, max_keys=1000, config=None):
- """
- Get instances in current region
- :param marker: start position
- :param max_keys: max count per page
- :param config:
- :return:
- """
- params = {}
- if marker is not None:
- params[b'marker'] = marker
- if max_keys is not None:
- params[b'maxKeys'] = max_keys
- return model.ListInstanceResponse(self._send_request(http_methods.GET,
- function_name='instance',
- params=params,
- config=config))
- @required(instance_id=(str))
- def get_instance_detail(self, instance_id, config=None):
- """
- Get instance detail
- :param instance_id: The ID of instance
- :type instance_id: string or unicode
- :param config: None
- :type config: BceClientConfiguration
- :return:
- {
- "instance_id":"scs-bj-cxisuftlkquj",
- "instance_name":"post101",
- "instance_status":"_running",
- "cluster_type":"master_slave",
- "engine":"redis",
- "engine_version":"3.2",
- "vnet_ip":"10.107.231.11",
- "domain":"redis.zsfqaybijgbv.scs.bj.baidubce.com",
- "port":"6379",
- "instance_create_time":"2018-11-13_t05:37:49_z",
- "capacity":1,
- "used_capacity":0.06,
- "payment_timing":"_postpaid",
- "vpc_id":"vpc-1n1wqxfu4iuu",
- "auto_renew":"true",
- "subnets":[
- {
- "name":"系统预定义子网_c",
- "subnet_id":"sbn-0ynnfkyymh8z",
- "zone_name":"cn-bj-c",
- "cidr":"192.168.32.0/20"
- },
- {
- "name":"系统预定义子网",
- "subnet_id":"sbn-rvv87cdd0gv9",
- "zone_name":"cn-bj-a",
- "cidr":"192.168.0.0/20"
- }
- ],
- "zone_names":[
- "cn-bj-a",
- "cn-bj-c"
- ]
- }
- """
- return model.GetInstanceResponse(self._send_request(http_methods.GET, function_name='instance', key=instance_id,
- config=config, api_version=2))
- @required(instance_id=(str), instance_name=(str))
- def rename_instance(self, instance_id, instance_name, config=None):
- """
- Update the instance_name of instance
- :param instance_id: the ID of instance
- :type str
- :param instance_name: a new instance name for instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {'instanceName': instance_name}
- key = instance_id + '/rename'
- return self._send_request(http_method=http_methods.PUT, function_name='instance', key=key,
- body=json.dumps(data), config=config, api_version=1)
- @required(instance_id=(str))
- def restart_instance(self, instance_id, config=None):
- """
- restart the instance
- :param instance_id: the ID of instance
- :type str
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- key = instance_id + '/restart'
- return self._send_request(http_method=http_methods.PUT, function_name='instance', key=key,
- config=config, api_version=2)
- @required(instance_id=(str), domain=(str))
- def rename_instance_domain(self, instance_id, domain, config=None):
- """
- Update the domain of instance
- :param instance_id: the ID of instance
- :type str
- :param domain: a new domain for instance.
- New instance domain name.
- Naming rules of domain name:
- 1. It is composed of lowercase letters and numbers;
- 2. It begins with a lowercase letter;
- 3. The length is between 3-30
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {'domain': domain}
- key = instance_id + '/renameDomain'
- return self._send_request(http_method=http_methods.PUT, function_name='instance', key=key,
- body=json.dumps(data), config=config, api_version=1)
- @required(instance_id=(str), password=(str))
- def flush_instance(self, instance_id, password='', config=None):
- """
- Clear the data of SCS instance
- :param instance_id: the ID of instance
- :type str
- :param password: the password of instance.
- if no password is set, an empty string is passed.
- The password needs to be encrypted.
- Please refer to the definition of password encryption transmission specification for details.
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- password = ''
- if len(password) > 0:
- secret_access_key = self.config.credentials.secret_access_key
- password = utils.aes128_encrypt_16char_key(password, secret_access_key)
- data = {
- 'password': password
- }
- key = instance_id + '/flush'
- return self._send_request(http_method=http_methods.PUT, function_name='instance', key=key,
- body=json.dumps(data), config=config, api_version=1)
- def list_available_zones(self, config=None):
- """
- lost available zone of current region
- :param config:
- :type BceClientConfiguration
- :return:
- """
- return model.ListAvailableZoneResponse(self._send_request(http_methods.GET, function_name="zone",
- config=config))
- def list_subnets(self, vpc_id=None, zone_name=None, config=None):
- """
- list subnet by vpcId or zoneName
- :param vpc_id: ID of the VPC to which it belongs
- :param zone_name: The name of the zone it belongs to
- :param config:
- :type BceClientConfiguration
- :return:
- """
- params = {}
- if vpc_id is not None:
- params[b'vpcId'] = vpc_id
- if zone_name is not None:
- params[b'zoneName'] = zone_name
- return model.ListSubnetResponse(self._send_request(http_methods.GET, function_name="subnet",
- params=params, config=config))
- def list_nodetypes(self, config=None):
- """
- List nodetypes
- :param config:
- :type BceClientConfiguration
- :return:
- """
- return model.ListNodeTypeResponse(self._send_request(http_methods.GET, function_name="nodetypes",
- config=config, api_version=2))
- @required(instance_id=(str), change_tags=list)
- def bind_tags(self, instance_id, change_tags, config=None):
- """
- Bind tags to instance
- :param change_tags: tag list to bind to instance
- :type list of Tag
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'changeTags': change_tags
- }
- key = instance_id + '/bindTag'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, body=json.dumps(data, cls=model.JsonWrapper, indent=4), config=config)
- @required(instance_id=(str), change_tags=list)
- def unbind_tags(self, instance_id, change_tags, config=None):
- """
- Unbind tags to instance
- :param change_tags: tag list to unbind
- :type list of Tag
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'changeTags': change_tags
- }
- key = instance_id + '/unBindTag'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, body=json.dumps(data, cls=model.JsonWrapper, indent=4), config=config)
- @required(instance_id=(str))
- def set_as_master(self, instance_id, config=None):
- """
- Set an SCS instance as the primary region of the live instance group
- The cluster created by default is master
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- key = instance_id + '/setAsMaster'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, config=config)
- @required(instance_id=(str), master_domain=(str), master_port=int)
- def set_as_slave(self, instance_id, master_domain, master_port, config=None):
- """
- Set SCS instance A as a slave of a master SCS instance B
- :param master_port: the port of master redis B
- :type int
- :param master_domain:the domain of master redis B
- if B in a different region,peer-2-peer dns copy muster be turn on.
- :type str/unicode
- :param instance_id: the ID of instance
- :type str/unicode
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'masterDomain': master_domain,
- 'masterPort': master_port
- }
- key = instance_id + '/setAsSlave'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, body=json.dumps(data), config=config)
- @required(instance_id=(str))
- def list_security_ip(self, instance_id, config=None):
- """
- List securityIps of a instance
- :param instance_id: ID of instanceId
- :param config:
- :return:
- """
- key = instance_id + "/securityIp"
- return model.ListSecurityIpResponse(self._send_request(http_methods.GET, function_name="instance",
- key=key, config=config))
- @required(instance_id=(str), security_ips=list)
- def add_security_ips(self, instance_id, security_ips, config=None):
- """
- Add security_ips to access to instance
- :param security_ips:
- :type list
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'securityIps': security_ips
- }
- key = instance_id + '/securityIp'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, body=json.dumps(data), config=config)
- @required(instance_id=(str), security_ips=list)
- def delete_security_ips(self, instance_id, security_ips, config=None):
- """
- Delete security_ips to access to instance
- :param security_ips:
- :type list
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'securityIps': security_ips
- }
- key = instance_id + '/securityIp'
- return self._send_request(http_method=http_methods.DELETE, function_name='instance',
- key=key, body=json.dumps(data), config=config)
- @required(instance_id=(str), password=(str))
- def modify_password(self, instance_id, password, config=None):
- """
- Update the password for scs instance
- :param password:
- :type list
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- secret_access_key = self.config.credentials.secret_access_key
- data = {
- 'password': utils.aes128_encrypt_16char_key(password, secret_access_key)
- }
- key = instance_id + '/modifyPassword'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, body=json.dumps(data), config=config)
- @required(instance_id=(str))
- def list_parameters(self, instance_id, config=None):
- """
- List parameters of a instance
- :param instance_id: ID of instanceId
- :param config:
- :return:
- """
- key = instance_id + "/parameter"
- return model.ListParameterResponse(self._send_request(http_methods.GET, function_name="instance",
- key=key, config=config))
- @required(instance_id=(str), name=(str), time=(str), expire_days=int)
- def modify_parameter(self, instance_id, name, value, config=None):
- """
- Update the parameter of instance
- :param name: parameter name
- :param value: parameter value
- :param instance_id: the ID of instance
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'parameter': {
- 'name': name,
- 'value': value
- }
- }
- key = instance_id + '/parameter'
- return self._send_request(http_method=http_methods.PUT, function_name='instance',
- key=key, body=json.dumps(data), config=config)
- @required(instance_id=(str))
- def list_backups(self, instance_id, config=None):
- """
- List backup of a instance
- :param instance_id: ID of instanceId
- :param config:
- :return:
- """
- key = instance_id + "/backup"
- return model.ListBackupResponse(self._send_request(http_methods.GET, function_name="instance",
- key=key, config=config))
- @required(instance_id=(str), backup_record_id=(str))
- def get_backup(self, instance_id, backup_record_id, config=None):
- """
- List backup of a instance
- :param backup_record_id: backup record ID
- :param instance_id: ID of instanceId
- :param config:
- :return:
- """
- key = instance_id + "/backup/" + backup_record_id
- return model.GetBackupResponse(self._send_request(http_methods.GET, function_name="instance",
- key=key, config=config))
- @required(instance_id=(str), days=(str), time=(str), expire_days=int)
- def modify_backup_policy(self, instance_id, days, time, expire_days, config=None):
- """
- Update the instance_name of instance
- :param instance_id: the ID of instance
- :type str
- :param expire_days: Backup file expiration time
- :type int
- :param time: when to backup.utc time.eg:01:05:00
- :param days: the duration to backup.eg:Sun,Wed,Thu,Fri,Sta
- :type str
- :param config: None
- :type BceClientConfiguration
- :return:
- """
- data = {
- 'backupDays': days,
- 'backupTime': time,
- 'expireDay': expire_days
- }
- key = instance_id + '/modifyBackupPolicy'
- return self._send_request(http_method=http_methods.PUT, function_name='instance', key=key,
- body=json.dumps(data), config=config)
- @staticmethod
- def _get_path_v1(config, function_name=None, key=None):
- return utils.append_uri(scs.URL_PREFIX_V1, function_name, key)
- @staticmethod
- def _get_path_v2(config, function_name=None, key=None):
- return utils.append_uri(scs.URL_PREFIX_V2, function_name, key)
- @staticmethod
- def _bce_scs_sign(credentials, http_method, path, headers, params,
- timestamp=0, expiration_in_seconds=1800,
- headers_to_sign=None):
- headers_to_sign_list = [b"host",
- b"content-md5",
- b"content-length",
- b"content-type"]
- if headers_to_sign is None or len(headers_to_sign) == 0:
- headers_to_sign = []
- for k in headers:
- k_lower = k.strip().lower()
- if k_lower.startswith(http_headers.BCE_PREFIX) or k_lower in headers_to_sign_list:
- headers_to_sign.append(k_lower)
- headers_to_sign.sort()
- else:
- for k in headers:
- k_lower = k.strip().lower()
- if k_lower.startswith(http_headers.BCE_PREFIX):
- headers_to_sign.append(k_lower)
- headers_to_sign.sort()
- return bce_v1_signer.sign(credentials,
- http_method,
- path,
- headers,
- params,
- timestamp,
- expiration_in_seconds,
- headers_to_sign)
- def _merge_config(self, config):
- if config is None:
- return self.config
- else:
- self._check_config_type(config)
- new_config = copy.copy(self.config)
- new_config.merge_non_none_values(config)
- return new_config
- def _send_request(self, http_method, function_name=None, key=None, body=None, headers=None, params=None,
- config=None, body_parser=None, api_version=1):
- if params is None:
- params = {"clientToken": uuid.uuid4()}
- config = self._merge_config(config)
- path = {
- 1: ScsClient._get_path_v1,
- 2: ScsClient._get_path_v2,
- }[api_version](config, function_name, key)
- if body_parser is None:
- body_parser = _parse_result
- if headers is None:
- headers = {b'Accept': b'*/*', b'Content-Type': b'application/json;charset=utf-8'}
- return bce_http_client.send_request(config, ScsClient._bce_scs_sign, [body_parser], http_method, path, body,
- headers, params)
|