def generate_url(self, key): """Generate webhook URL with proper format. :param key: Key string to be used for decrypt the credentials. """ senlin_creds = context.get_service_context() kc = driver_base.SenlinDriver().identity(senlin_creds) senlin_service = kc.service_get('clustering', 'senlin') if not senlin_service: resource = _('service:type=clustering,name=senlin') raise exception.ResourceNotFound(resource=resource) senlin_service_id = senlin_service['id'] region = cfg.CONF.region_name_for_services endpoint = kc.endpoint_get(senlin_service_id, region, 'public') if not endpoint: resource = _('endpoint: service=%(service)s,region=' '%(region)s,visibility=%(interface)s') % { 'service': senlin_service_id, 'region': region, 'interface': 'public' } raise exception.ResourceNotFound(resource=resource) endpoint_url = endpoint['url'].replace('$(tenant_id)s', self.project) location = endpoint_url + '/webhooks/%s/trigger' % self.id location += "?%s" % parse.urlencode({'key': key}) return location, key
def detach(self, cluster): """Routine to be called when the policy is detached from a cluster. :param cluster: The cluster from which the policy is to be detached. :returns: When the operation was successful, returns a tuple of (True, data) where the data contains references to the resources created; otherwise returns a tuple of (False, err) where the err contains a error message. """ reason = _('LB resources deletion succeeded.') params = self._build_conn_params(cluster) lb_driver = driver_base.SenlinDriver().loadbalancing(params) cp = cluster_policy.ClusterPolicy.load(oslo_context.get_current(), cluster.id, self.id) policy_data = self._extract_policy_data(cp.data) if policy_data is None: return True, reason res, reason = lb_driver.lb_delete(**policy_data) if res is False: return False, reason nodes = node_mod.Node.load_all(oslo_context.get_current(), cluster_id=cluster.id) for node in nodes: if 'lb_member' in node.data: node.data.pop('lb_member') node.store(oslo_context.get_current()) return True, reason
def heat(self, obj): '''Construct heat client using the combined context.''' if self.hc: return self.hc params = self._build_conn_params(obj.user, obj.project) self.hc = driver_base.SenlinDriver().orchestration(params) return self.hc
def _get_base_url(self): base = None service_cred = senlin_context.get_service_credentials() kc = driver_base.SenlinDriver().identity(service_cred) try: base = kc.get_senlin_endpoint() except exception.InternalError as ex: LOG.warning('Senlin endpoint can not be found: %s.', ex) return base
def test_init_using_specified_cloud_backend(self): plugin2 = mock.Mock() plugin2.compute = 'Compute2' plugin2.orchestration = 'Orchestration2' env = environment.global_env() env.register_driver('openstack_test', plugin2) sd = driver_base.SenlinDriver('openstack_test') self.assertEqual('Compute2', sd.compute) self.assertEqual('Orchestration2', sd.orchestration)
def get_service_context(**kwargs): '''An abstraction layer for getting service credential. There could be multiple cloud backends for senlin to use. This abstraction layer provides an indirection for senlin to get the credentials of 'senlin' user on the specific cloud. By default, this credential refers to the credentials built for keystone middleware in an OpenStack cloud. ''' identity_service = driver_base.SenlinDriver().identity return identity_service.get_service_credentials(**kwargs)
def delete(self, ctx, identifier): """Delete an alarm. :param identifier: This must be an alarm ID. """ try: cc = driver_base.SenlinDriver().telemetry(ctx) res = cc.alarm_delete(identifier, True) return True, res except exc.InternalError as ex: return False, six.text_type(ex)
def test_init_using_default_cloud_backend(self): plugin1 = mock.Mock() plugin1.compute = 'Compute1' plugin1.orchestration = 'Orchestration1' env = environment.global_env() env.register_driver('openstack_test', plugin1) cfg.CONF.set_override('cloud_backend', 'openstack_test') sd = driver_base.SenlinDriver() self.assertEqual('Compute1', sd.compute) self.assertEqual('Orchestration1', sd.orchestration)
def keystone(self, user, project): """Construct keystone client based on object. :param user: The ID of the requesting user. :param project: The ID of the requesting project. :returns: A reference to the keystone client. """ if self._keystoneclient is not None: return self._keystoneclient params = self._build_conn_params(user, project) self._keystoneclient = driver.SenlinDriver().identity(params) return self._keystoneclient
def nova(self, obj): """Construct nova client based on object. :param obj: Object for which the client is created. It is expected to be None when retrieving an existing client. When creating a client, it conatins the user and project to be used. """ if self._novaclient is not None: return self._novaclient params = self._build_conn_params(obj) self._novaclient = driver.SenlinDriver().compute(params) return self._novaclient
def network(self, obj): """Construct network client based on object. :param obj: Object for which the client is created. It is expected to be None when retrieving an existing client. When creating a client, it contains the user and project to be used. """ if self._networkclient is not None: return self._networkclient params = self._build_conn_params(obj.user, obj.project) self._networkclient = driver_base.SenlinDriver().network(params) return self._networkclient
def _get_token(self, **kwargs): """Get a valid token based on the credential provided. :param cred: Rebuilt credential dictionary for authentication. """ try: token = driver_base.SenlinDriver().identity.get_token(**kwargs) except Exception as ex: LOG.exception('Webhook failed authentication: %s.', ex) raise exc.Forbidden() return token
def post_op(self, cluster_id, action): """Routine to be called after an action has been executed. For this particular policy, we take this chance to update the pool maintained by the load-balancer. :param cluster_id: The ID of the cluster on which a relevant action has been executed. :param action: The action object that triggered this operation. :returns: Nothing. """ # TODO(Yanyanhu): Need special handling for cross-az scenario # which is supported by Neutron lbaas. creation = action.data.get('creation', None) nodes_added = creation.get('nodes', []) if creation else [] if len(nodes_added) == 0: return db_cluster = co.Cluster.get(action.context, cluster_id) params = self._build_conn_params(db_cluster) lb_driver = driver_base.SenlinDriver().loadbalancing(params) cp = cluster_policy.ClusterPolicy.load(action.context, cluster_id, self.id) policy_data = self._extract_policy_data(cp.data) lb_id = policy_data['loadbalancer'] pool_id = policy_data['pool'] port = self.pool_spec.get(self.POOL_PROTOCOL_PORT) subnet = self.pool_spec.get(self.POOL_SUBNET) # Add new nodes to lb pool for node_id in nodes_added: node = nm.Node.load(action.context, node_id=node_id) member_id = node.data.get('lb_member', None) if member_id: LOG.warning(_LW('Node %(n)s already in lb pool %(p)s.'), { 'n': node_id, 'p': pool_id }) continue member_id = lb_driver.member_add(node, lb_id, pool_id, port, subnet) if member_id is None: action.data['status'] = base.CHECK_ERROR action.data['reason'] = _('Failed in adding new node(s) ' 'into lb pool.') return node.data.update({'lb_member': member_id}) node.store(action.context) return
def network(self, user, project): """Construct network client based on user and project. :param user: The ID of the requesting user. :param project: The ID of the requesting project. :returns: A reference to the network client. """ if self._networkclient is not None: return self._networkclient params = self._build_conn_params(user, project) self._networkclient = driver.SenlinDriver().network(params) return self._networkclient
def lbaas(self, user, project): """Construct LB service client based on user and project. :param user: The ID of the requesting user. :param project: The ID of the requesting project. :returns: A reference to the LB service client. """ if self._lbaasclient is not None: return self._lbaasclient params = self._build_conn_params(user, project) self._lbaasclient = driver.SenlinDriver().loadbalancing(params) return self._lbaasclient
def test_init_using_default_cloud_backend(self): plugin1 = mock.Mock() plugin1.compute = 'Compute1' plugin1.orchestration = 'Orchestration1' env = environment.global_env() env.register_driver('cloud_backend_1', plugin1) # Using default cloud backend defined in configure file cfg.CONF.set_override('cloud_backend', 'cloud_backend_1', enforce_type=True) sd = driver_base.SenlinDriver() self.assertEqual('Compute1', sd.compute) self.assertEqual('Orchestration1', sd.orchestration)
def _get_trust(self, req): """List trusts with current user as the trustor. :param req: The WSGI request object. :return: ID of the trust or exception of InternalError. """ rpcc = rpc.EngineClient() ctx = req.context params = {'user': ctx.user_id, 'project': ctx.project_id} obj = util.parse_request('CredentialGetRequest', req, params) res = rpcc.call(ctx, 'credential_get', obj) if res: trust_id = res.get('trust', None) if trust_id: return trust_id params = { 'auth_url': ctx.auth_url, 'token': ctx.auth_token, 'project_id': ctx.project_id, 'user_id': ctx.user_id, } kc = driver_base.SenlinDriver().identity(params) service_cred = context.get_service_credentials() admin_id = kc.get_user_id(**service_cred) try: trust = kc.trust_get_by_trustor(ctx.user_id, admin_id, ctx.project_id) except exception.InternalError as ex: if ex.code == 400: trust = None else: raise if not trust: # Create a trust if no existing one found trust = kc.trust_create(ctx.user_id, admin_id, ctx.project_id, ctx.roles) # If credential not exists, create it, otherwise update it. cred = {'openstack': {'trust': trust.id}} params = {'cred': cred} obj = util.parse_request('CredentialCreateRequest', req, params) rpcc.call(ctx, 'credential_create', obj) return trust.id
def attach(self, cluster): """Routine to be invoked when policy is to be attached to a cluster. :param cluster: The target cluster to be attached to; :returns: When the operation was successful, returns a tuple (True, message); otherwise, return a tuple (False, error). """ res, data = super(LoadBalancingPolicy, self).attach(cluster) if res is False: return False, data nodes = node_mod.Node.load_all(oslo_context.get_current(), cluster_id=cluster.id) params = self._build_conn_params(cluster) lb_driver = driver_base.SenlinDriver().loadbalancing(params) res, data = lb_driver.lb_create(self.vip_spec, self.pool_spec, self.hm_spec) if res is False: return False, data port = self.pool_spec.get(self.POOL_PROTOCOL_PORT) subnet = self.pool_spec.get(self.POOL_SUBNET) for node in nodes: member_id = lb_driver.member_add(node, data['loadbalancer'], data['pool'], port, subnet) if member_id is None: # When failed in adding member, remove all lb resources that # were created and return the failure reason. # TODO(anyone): May need to "roll-back" changes caused by any # successful member_add() calls. lb_driver.lb_delete(**data) return False, 'Failed in adding node into lb pool' node.data.update({'lb_member': member_id}) node.store(oslo_context.get_current()) cluster_data_lb = cluster.data.get('loadbalancers', {}) cluster_data_lb[self.id] = {'vip_address': data.pop('vip_address')} cluster.data['loadbalancers'] = cluster_data_lb policy_data = self._build_policy_data(data) return True, policy_data
def pre_op(self, cluster_id, action): """Routine to be called before an action has been executed. For this particular policy, we take this chance to update the pool maintained by the load-balancer. :param cluster_id: The ID of the cluster on which a relevant action has been executed. :param action: The action object that triggered this operation. :returns: Nothing. """ candidates = self._get_delete_candidates(cluster_id, action) if len(candidates) == 0: return db_cluster = co.Cluster.get(action.context, cluster_id) params = self._build_conn_params(db_cluster) lb_driver = driver_base.SenlinDriver().loadbalancing(params) cp = cluster_policy.ClusterPolicy.load(action.context, cluster_id, self.id) policy_data = self._extract_policy_data(cp.data) lb_id = policy_data['loadbalancer'] pool_id = policy_data['pool'] # Remove nodes that will be deleted from lb pool for node_id in candidates: node = nm.Node.load(action.context, node_id=node_id) member_id = node.data.get('lb_member', None) if member_id is None: LOG.warning(_LW('Node %(n)s not found in lb pool %(p)s.'), { 'n': node_id, 'p': pool_id }) continue res = lb_driver.member_remove(lb_id, pool_id, member_id) if res is not True: action.data['status'] = base.CHECK_ERROR action.data['reason'] = _('Failed in removing deleted ' 'node(s) from lb pool.') return return
def attach(self, cluster): """Routine to be invoked when policy is to be attached to a cluster. :param cluster: The target cluster to be attached to; :returns: When the operation was successful, returns a tuple (True, message); otherwise, return a tuple (False, error). """ res, data = super(LoadBalancingPolicy, self).attach(cluster) if res is False: return False, data nodes = node_mod.Node.load_all(oslo_context.get_current(), cluster_id=cluster.id) params = self._build_conn_params(cluster) lb_driver = driver_base.SenlinDriver().loadbalancing(params) res, data = lb_driver.lb_create(self.vip_spec, self.pool_spec) if res is False: return False, data port = self.pool_spec.get(self.POOL_PROTOCOL_PORT) subnet = self.pool_spec.get(self.POOL_SUBNET) for node in nodes: member_id = lb_driver.member_add(node, data['loadbalancer'], data['pool'], port, subnet) if member_id is None: # When failed in adding member, remove all lb resources that # were created and return the failure reason. # TODO(Yanyan Hu): Maybe we should tolerate member adding # failure and allow policy attaching to succeed without # all nodes being added into lb pool? lb_driver.lb_delete(**data) return False, 'Failed in adding node into lb pool' node.data.update({'lb_member': member_id}) node.store(oslo_context.get_current()) policy_data = self._build_policy_data(data) return True, policy_data
def _get_trust(self, ctx): """List trusts with current user as the trustor. :param ctx: The requesting context. :return: ID of the trust or exception of InternalError. """ rpcc = rpc.EngineClient() res = rpcc.credential_get(ctx) if res: trust_id = res.get('trust', None) if trust_id: return trust_id params = { 'auth_url': ctx.auth_url, 'token': ctx.auth_token, 'project_id': ctx.project, 'user_id': ctx.user, } kc = driver_base.SenlinDriver().identity(params) service_cred = context.get_service_context() admin_id = kc.get_user_id(**service_cred) try: trust = kc.trust_get_by_trustor(ctx.user, admin_id, ctx.project) except exception.InternalError as ex: if ex.code == 400: trust = None else: raise ex if not trust: # Create a trust if no existing one found trust = kc.trust_create(ctx.user, admin_id, ctx.project, ctx.roles) # If credential not exists, create it, otherwise update it. rpcc.credential_create(ctx, trust.id) return trust.id
def create(self, ctx, **kwargs): """Create an alarm for a cluster. :param name: The name for the alarm. :param urls: A list of URLs for webhooks to be triggered. :returns: A dict containing properties of the alarm. """ self.ok_actions = kwargs.get(OK_ACTIONS, []) self.alarm_actions = kwargs.get(ALARM_ACTIONS, []) self.insufficient_data_actions = kwargs.get(INSUFFICIENT_DATA_ACTIONS, []) rule_name = self.namespace + '_rule' rule_data = dict((k, v) for k, v in self.rule.items()) params = { NAME: self.name, DESCRIPTION: self.desc, TYPE: self.namespace, STATE: self.state, SEVERITY: self.severity, ENABLED: self.enabled, OK_ACTIONS: self.ok_actions, ALARM_ACTIONS: self.alarm_actions, INSUFFICIENT_DATA_ACTIONS: self.insufficient_data_actions, TIME_CONSTRAINTS: self.alarm_properties[TIME_CONSTRAINTS], REPEAT: self.alarm_properties[REPEAT], rule_name: rule_data, } try: cc = driver_base.SenlinDriver().telemetry(ctx.to_dict()) alarm = cc.alarm_create(**params) self.physical_id = alarm.id self.store(ctx) return True, alarm.to_dict() except exc.SenlinException as ex: return False, six.text_type(ex)
def post_op(self, cluster_id, action): """Routine to be called after an action has been executed. For this particular policy, we take this chance to update the pool maintained by the load-balancer. :param cluster_id: The ID of the cluster on which a relevant action has been executed. :param action: The action object that triggered this operation. :returns: Nothing. """ nodes_added = action.outputs.get('nodes_added', []) nodes_removed = action.outputs.get('nodes_removed', []) if ((len(nodes_added) == 0) and (len(nodes_removed) == 0)): return db_cluster = db_api.cluster_get(action.context, cluster_id) params = self._build_conn_params(db_cluster) lb_driver = driver_base.SenlinDriver().loadbalancing(params) cp = cluster_policy.ClusterPolicy.load(action.context, cluster_id, self.id) policy_data = self._extract_policy_data(cp.data) lb_id = policy_data['loadbalancer'] pool_id = policy_data['pool'] port = self.pool_spec.get(self.POOL_PROTOCOL_PORT) subnet = self.pool_spec.get(self.POOL_SUBNET) # Remove nodes that have been deleted from lb pool for node_id in nodes_removed: node = node_mod.Node.load(action.context, node_id=node_id, show_deleted=True) member_id = node.data.get('lb_member', None) if member_id is None: LOG.warning(_LW('Node %(n)s not found in lb pool %(p)s.'), {'n': node_id, 'p': pool_id}) continue res = lb_driver.member_remove(lb_id, pool_id, member_id) if res is not True: action.data['status'] = base.CHECK_ERROR action.data['reason'] = _('Failed in removing deleted ' 'node(s) from lb pool.') return # Add new nodes to lb pool for node_id in nodes_added: node = node_mod.Node.load(action.context, node_id=node_id, show_deleted=True) member_id = node.data.get('lb_member', None) if member_id: LOG.warning(_LW('Node %(n)s already in lb pool %(p)s.'), {'n': node_id, 'p': pool_id}) continue member_id = lb_driver.member_add(node, lb_id, pool_id, port, subnet) if member_id is None: action.data['status'] = base.CHECK_ERROR action.data['reason'] = _('Failed in adding new node(s) ' 'into lb pool.') return node.data.update({'lb_member': member_id}) node.store(action.context) return
def get_service_context(**kwargs): """Get a customized service context.""" identity_service = driver_base.SenlinDriver().identity creds = identity_service.get_service_credentials(**kwargs) return RequestContext.from_dict(creds)
def zaqar(self): if self._zaqarclient is not None: return self._zaqarclient params = self._build_conn_params(self.user, self.project) self._zaqarclient = driver_base.SenlinDriver().message(params) return self._zaqarclient
def keystone(self): if self._keystoneclient is not None: return self._keystoneclient params = self._build_conn_params(self.user, self.project) self._keystoneclient = driver_base.SenlinDriver().identity(params) return self._keystoneclient
def workflow(self, obj): if self._workflowclient is not None: return self._workflowclient params = self._build_conn_params(obj.user, obj.project) self._workflowclient = driver_base.SenlinDriver().workflow(params) return self._workflowclient