def _create_network(self, obj): client = self.network(obj) try: net = client.network_create() subnet = client.subnet_create(network_id=net.id, cidr='10.7.0.0/24', ip_version=4) except exc.InternalError as ex: raise exc.EResourceCreation(type='kubernetes', message=str(ex), resource_id=obj.id) pub_net = client.network_get(self.properties[self.PUBLIC_NETWORK]) try: router = client.router_create( external_gateway_info={"network_id": pub_net.id}) client.add_interface_to_router(router, subnet_id=subnet.id) fip = client.floatingip_create(floating_network_id=pub_net.id) except exc.InternalError as ex: raise exc.EResourceCreation(type='kubernetes', message=str(ex), resource_id=obj.id) ctx = context.get_service_context(user_id=obj.user, project_id=obj.project) data = obj.data data[self.PRIVATE_NETWORK] = net.id data[self.PRIVATE_SUBNET] = subnet.id data[self.PRIVATE_ROUTER] = router.id data[self.KUBE_MASTER_FLOATINGIP] = fip.floating_ip_address data[self.KUBE_MASTER_FLOATINGIP_ID] = fip.id cluster_obj.Cluster.update(ctx, obj.id, {'data': data}) return net.id
def _validate_flavor(self, obj, name_or_id, reason=None): flavor = None msg = '' try: flavor = self.compute(obj).flavor_find(name_or_id, False) except exc.InternalError as ex: msg = six.text_type(ex) if reason is None: # reaons is 'validate' if ex.code == 404: msg = _( "The specified %(k)s '%(v)s' could not be found.") % { 'k': self.FLAVOR, 'v': name_or_id } raise exc.InvalidSpec(message=msg) else: raise if flavor is not None: if not flavor.is_disabled: return flavor msg = _("The specified %(k)s '%(v)s' is disabled") % { 'k': self.FLAVOR, 'v': name_or_id } if reason == 'create': raise exc.EResourceCreation(type='server', message=msg) elif reason == 'update': raise exc.EResourceUpdate(type='server', id=obj.physical_id, message=msg) else: raise exc.InvalidSpec(message=msg)
def do_create(self, obj): """Create a heat stack using the given node object. :param obj: The node object to operate on. :returns: The UUID of the heat stack created. """ kwargs = { 'stack_name': obj.name + '-' + utils.random_name(8), 'template': self.properties[self.TEMPLATE], 'template_url': self.properties[self.TEMPLATE_URL], 'timeout_mins': self.properties[self.TIMEOUT], 'disable_rollback': self.properties[self.DISABLE_ROLLBACK], 'parameters': self.properties[self.PARAMETERS], 'files': self.properties[self.FILES], 'environment': self.properties[self.ENVIRONMENT], } try: stack = self.orchestration(obj).stack_create(**kwargs) # Timeout = None means we will use the 'default_action_timeout' # It can be overridden by the TIMEOUT profile propertie timeout = None if self.properties[self.TIMEOUT]: timeout = self.properties[self.TIMEOUT] * 60 self.orchestration(obj).wait_for_stack(stack.id, 'CREATE_COMPLETE', timeout=timeout) return stack.id except exc.InternalError as ex: raise exc.EResourceCreation(type='stack', message=ex.message)
def _get_master_cluster_info(self, obj): ctx = context.get_service_context(user_id=obj.user, project_id=obj.project) master = self.properties[self.MASTER_CLUSTER] try: cluster = cluster_obj.Cluster.find(ctx, master) except Exception as ex: raise exc.EResourceCreation(type='kubernetes.worker', message=six.text_type(ex)) for key in self.MASTER_CLUSTER_KEYS: if key not in cluster.data: raise exc.EResourceCreation( type='kubernetes.worker', message="Can't find %s in cluster %s" % (key, master)) return cluster.data
def post_lifecycle_hook_message(self, lifecycle_action_token, node_id, resource_id, lifecycle_transition_type): message_list = [{ "ttl": CONF.notification.ttl, "body": { "lifecycle_action_token": lifecycle_action_token, "node_id": node_id, "resource_id": resource_id, "lifecycle_transition_type": lifecycle_transition_type } }] try: if not self.zaqar().queue_exists(self.queue_name): kwargs = { "_max_messages_post_size": CONF.notification.max_message_size, "description": "Senlin lifecycle hook notification", "name": self.queue_name } self.zaqar().queue_create(**kwargs) return self.zaqar().message_post(self.queue_name, message_list) except exception.InternalError as ex: raise exception.EResourceCreation(type='queue', message=six.text_type(ex))
def do_create(self, obj): """Create a container instance using the given profile. :param obj: The node object for this container. :returns: ID of the container instance or ``None`` if driver fails. :raises: `EResourceCreation` """ name = self.properties[self.NAME] if name is None: name = '-'.join([obj.name, utils.random_name()]) params = { 'image': self.properties[self.IMAGE], 'name': name, 'command': self.properties[self.COMMAND], } try: ctx = context.get_service_context(project=obj.project, user=obj.user) dockerclient = self.docker(obj) db_api.node_add_dependents(ctx, self.host.id, obj.id) container = dockerclient.container_create(**params) dockerclient.start(container['Id']) except exc.InternalError as ex: raise exc.EResourceCreation(type='container', message=str(ex)) self.container_id = container['Id'][:36] return self.container_id
def _build_trust(self): # Get zaqar trustee user ID for trust building auth = ks_loading.load_auth_from_conf_options(CONF, 'zaqar') session = ks_loading.load_session_from_conf_options(CONF, 'zaqar') zaqar_trustee_user_id = session.get_user_id(auth=auth) try: trust = self.keystone().trust_get_by_trustor( self.user, zaqar_trustee_user_id, self.project) if not trust: # Create a trust if no existing one found roles = self.notifier_roles for role in roles: # Remove 'admin' role from delegated roles list # unless it is the only role user has if role == 'admin' and len(roles) > 1: roles.remove(role) trust = self.keystone().trust_create(self.user, zaqar_trustee_user_id, self.project, roles) except exc.InternalError as ex: msg = _('Can not build trust between user %(user)s and zaqar ' 'service user %(zaqar)s for receiver %(receiver)s.') % { 'user': self.user, 'zaqar': zaqar_trustee_user_id, 'receiver': self.id } LOG.error(msg) raise exc.EResourceCreation(type='trust', message=ex.message) return trust.id
def test_do_create_invalid_image(self): profile = server.ServerProfile('s2', self.spec) err = exc.EResourceCreation(type='server', message='boom') mock_image = self.patchobject(profile, '_validate_image', side_effect=err) node_obj = mock.Mock() self.assertRaises(exc.EResourceCreation, profile.do_create, node_obj) mock_image.assert_called_once_with(node_obj, 'FAKE_IMAGE', 'create')
def test_do_create_invalid_keypair(self): profile = server.ServerProfile('s2', self.spec) self._stubout_profile(profile, mock_image=True, mock_flavor=True) err = exc.EResourceCreation(type='server', message='boom') mock_kp = self.patchobject(profile, '_validate_keypair', side_effect=err) node_obj = mock.Mock() self.assertRaises(exc.EResourceCreation, profile.do_create, node_obj) mock_kp.assert_called_once_with(node_obj, 'FAKE_KEYNAME', 'create')
def _validate_az(self, obj, az_name, reason=None): try: res = self.compute(obj).validate_azs([az_name]) except exc.InternalError as ex: if reason == 'create': raise exc.EResourceCreation(type='server', message=six.text_type(ex)) else: raise if not res: msg = _("The specified %(key)s '%(value)s' could not be found") % { 'key': self.AVAILABILITY_ZONE, 'value': az_name } if reason == 'create': raise exc.EResourceCreation(type='server', message=msg) else: raise exc.InvalidSpec(message=msg) return az_name
def test_do_recover_with_recreate_failed_create(self): profile = self._create_profile('test-profile') self.patchobject(profile, 'do_delete', return_value=True) err = exception.EResourceCreation(type='STACK', message='BANNG') self.patchobject(profile, 'do_create', side_effect=err) ex = self.assertRaises(exception.EResourceOperation, profile.do_recover, mock.Mock(id='NODE_ID'), operation='RECREATE') msg = ("Failed in recovering node NODE_ID: Failed in creating " "STACK: BANNG.") self.assertEqual(msg, six.text_type(ex))
def _create_queue(self): queue_name = "senlin-receiver-%s" % self.id kwargs = { "_max_messages_post_size": CONF.receiver.max_message_size, "description": "Senlin receiver %s." % self.id, "name": queue_name } try: self.zaqar().queue_create(**kwargs) except exc.InternalError as ex: raise exc.EResourceCreation(type='queue', message=ex.message) return queue_name
def test_node_create_not_created(self, mock_create, mock_status): node = nodem.Node('node1', PROFILE_ID, CLUSTER_ID, self.context) mock_create.side_effect = exception.EResourceCreation( type='PROFILE', message='Boom', resource_id='test_id') res = node.do_create(self.context) self.assertFalse(res) mock_status.assert_any_call(self.context, consts.NS_CREATING, 'Creation in progress') mock_status.assert_any_call(self.context, consts.NS_ERROR, 'Failed in creating PROFILE: Boom.', physical_id='test_id')
def _set_security_group_rules(self, obj, sgid): client = self.network(obj) open_ports = { 'tcp': [22, 80, 8000, 8080, 6443, 8001, 8443, 443, 179, 8082, 8086], 'udp': [8285, 8472], 'icmp': [None] } for p in open_ports.keys(): for port in open_ports[p]: try: client.security_group_rule_create(sgid, port, protocol=p) except Exception as ex: raise exc.EResourceCreation(type='kubernetes', message=str(ex))
def _create_security_group(self, obj): ctx = context.get_service_context(user_id=obj.user, project_id=obj.project) sgid = obj.data.get(self.SECURITY_GROUP, None) if sgid: return sgid client = self.network(obj) try: sg = client.security_group_create(name=self.name) except Exception as ex: raise exc.EResourceCreation(type='kubernetes', message=str(ex)) data = obj.data data[self.SECURITY_GROUP] = sg.id cluster_obj.Cluster.update(ctx, obj.id, {'data': data}) self._set_security_group_rules(obj, sg.id) return sg.id
def _validate_keypair(self, obj, name_or_id, reason=None): try: return self.compute(obj).keypair_find(name_or_id, False) except exc.InternalError as ex: if reason == 'create': raise exc.EResourceCreation(type='server', message=six.text_type(ex)) elif reason == 'update': raise exc.EResourceUpdate(type='server', id=obj.physical_id, message=six.text_type(ex)) elif ex.code == 404: msg = _("The specified %(k)s '%(v)s' could not be found.") % { 'k': self.KEY_NAME, 'v': name_or_id } raise exc.InvalidSpec(message=msg) else: raise
def _create_subscription(self, queue_name): subscriber = self._generate_subscriber_url() trust_id = self._build_trust() # FIXME(Yanyanhu): For Zaqar doesn't support to create a # subscription that never expires, we specify a very large # ttl value which doesn't exceed the max time of python. kwargs = { "ttl": 2**36, "subscriber": subscriber, "options": { "trust_id": trust_id } } try: subscription = self.zaqar().subscription_create( queue_name, **kwargs) except exc.InternalError as ex: raise exc.EResourceCreation(type='subscription', message=str(ex)) return subscription
def test_do_create_invalid_network(self): cc = mock.Mock() nc = mock.Mock() node_obj = mock.Mock(id='FAKE_NODE_ID', data={}, index=123, cluster_id='FAKE_CLUSTER_ID') spec = { 'type': 'os.nova.server', 'version': '1.0', 'properties': { 'flavor': 'FLAV', 'image': 'FAKE_IMAGE', 'key_name': 'FAKE_KEYNAME', 'name': 'FAKE_SERVER_NAME', 'networks': [{ 'network': 'FAKE_NET' }] } } profile = server.ServerProfile('s2', spec) profile._computeclient = cc profile._networkclient = nc self._stubout_profile(profile, mock_image=True, mock_flavor=True, mock_keypair=True) err = exc.EResourceCreation(type='server', message='FOO') mock_net = self.patchobject(profile, '_validate_network', side_effect=err) self.assertRaises(exc.EResourceCreation, profile.do_create, node_obj) mock_net.assert_called_once_with(node_obj, { 'network': 'FAKE_NET', 'port': None, 'fixed_ip': None }, 'create')
def test_post_lifecycle_hook_message_queue_retry(self, mock_zaqar): cfg.CONF.set_override('max_message_size', 8192, 'notification') mock_zc = mock.Mock() mock_zaqar.return_value = mock_zc queue_name = 'my_queue' message = mmod.Message(queue_name) mock_zc.queue_exists.return_value = True test_exception = exception.EResourceCreation(type='queue', message="test") mock_zc.message_post.side_effect = [ test_exception, test_exception, None ] lifecycle_action_token = 'ACTION_ID' node_id = 'NODE_ID' resource_id = 'RESOURCE_ID' lifecycle_transition_type = 'TYPE' message.post_lifecycle_hook_message(lifecycle_action_token, node_id, resource_id, lifecycle_transition_type) mock_zc.queue_create.assert_not_called() self.assertEqual(3, mock_zc.message_post.call_count)
def do_create(self, obj): """Create a server for the node object. :param obj: The node object for which a server will be created. """ kwargs = {} for key in self.KEYS: # context is treated as connection parameters if key == self.CONTEXT: continue if self.properties[key] is not None: kwargs[key] = self.properties[key] admin_pass = self.properties[self.ADMIN_PASS] if admin_pass: kwargs.pop(self.ADMIN_PASS) kwargs['adminPass'] = admin_pass auto_disk_config = self.properties[self.AUTO_DISK_CONFIG] kwargs.pop(self.AUTO_DISK_CONFIG) kwargs['OS-DCF:diskConfig'] = 'AUTO' if auto_disk_config else 'MANUAL' image_ident = self.properties[self.IMAGE] if image_ident is not None: image = self._validate_image(obj, image_ident, 'create') kwargs.pop(self.IMAGE) kwargs['imageRef'] = image.id flavor_ident = self.properties[self.FLAVOR] flavor = self._validate_flavor(obj, flavor_ident, 'create') kwargs.pop(self.FLAVOR) kwargs['flavorRef'] = flavor.id keypair_name = self.properties[self.KEY_NAME] if keypair_name: keypair = self._validate_keypair(obj, keypair_name, 'create') kwargs['key_name'] = keypair.name kwargs['name'] = self.properties[self.NAME] or obj.name metadata = self._build_metadata(obj, self.properties[self.METADATA]) kwargs['metadata'] = metadata block_device_mapping_v2 = self.properties[self.BLOCK_DEVICE_MAPPING_V2] if block_device_mapping_v2 is not None: kwargs['block_device_mapping_v2'] = self._resolve_bdm( block_device_mapping_v2) user_data = self.properties[self.USER_DATA] if user_data is not None: ud = encodeutils.safe_encode(user_data) kwargs['user_data'] = encodeutils.safe_decode(base64.b64encode(ud)) networks = self.properties[self.NETWORKS] if networks is not None: kwargs['networks'] = [] for net_spec in networks: net = self._validate_network(obj, net_spec, 'create') kwargs['networks'].append(net) secgroups = self.properties[self.SECURITY_GROUPS] if secgroups: kwargs['security_groups'] = [{'name': sg} for sg in secgroups] if 'placement' in obj.data: if 'zone' in obj.data['placement']: kwargs['availability_zone'] = obj.data['placement']['zone'] if 'servergroup' in obj.data['placement']: group_id = obj.data['placement']['servergroup'] hints = self.properties.get(self.SCHEDULER_HINTS, {}) hints.update({'group': group_id}) kwargs['scheduler_hints'] = hints server = None resource_id = 'UNKNOWN' try: server = self.compute(obj).server_create(**kwargs) self.compute(obj).wait_for_server(server.id) return server.id except exc.InternalError as ex: if server and server.id: resource_id = server.id raise exc.EResourceCreation(type='server', message=ex.message, resource_id=resource_id)
def _validate_network(self, obj, network, reason=None): result = {} error = None # check network net_ident = network.get(self.NETWORK) if net_ident: try: net = self.network(obj).network_get(net_ident) if reason == 'update': result['net_id'] = net.id else: result['uuid'] = net.id except exc.InternalError as ex: error = six.text_type(ex) # check port port_ident = network.get(self.PORT) if not error and port_ident: try: port = self.network(obj).port_find(port_ident) if port.status != 'DOWN': error = _( "The status of the port %(port)s must be DOWN") % { 'port': port_ident } if reason == 'update': result['port_id'] = port.id else: result['port'] = port.id except exc.InternalError as ex: error = six.text_type(ex) elif port_ident is None and net_ident is None: error = _("'%(port)s' is required if '%(net)s' is omitted") % { 'port': self.PORT, 'net': self.NETWORK } fixed_ip = network.get(self.FIXED_IP) if not error and fixed_ip: if port_ident is not None: error = _("The '%(port)s' property and the '%(fixed_ip)s' " "property cannot be specified at the same time") % { 'port': self.PORT, 'fixed_ip': self.FIXED_IP } else: if reason == 'update': result['fixed_ips'] = [{'ip_address': fixed_ip}] else: result['fixed_ip'] = fixed_ip if error: if reason == 'create': raise exc.EResourceCreation(type='server', message=error) elif reason == 'update': raise exc.EResourceUpdate(type='server', id=obj.physical_id, message=error) else: raise exc.InvalidSpec(message=error) return result
def do_create(self, obj): """Create a server for the node object. :param obj: The node object for which a server will be created. """ kwargs = {} for key in self.KEYS: if self.properties[key] is not None: kwargs[key] = self.properties[key] image_ident = self.properties[self.IMAGE] if image_ident is not None: image = self._validate_image(obj, image_ident, 'create') kwargs.pop(self.IMAGE) kwargs['imageRef'] = image.id flavor_ident = self.properties[self.FLAVOR] flavor = self._validate_flavor(obj, flavor_ident, 'create') kwargs.pop(self.FLAVOR) kwargs['flavorRef'] = flavor.id keypair_name = self.properties[self.KEY_NAME] if keypair_name: keypair = self._validate_keypair(obj, keypair_name, 'create') kwargs['key_name'] = keypair.name kwargs['name'] = obj.name metadata = self._build_metadata(obj, {}) kwargs['metadata'] = metadata jj_vars = {} cluster_data = self._get_cluster_data(obj) kwargs['networks'] = [{'uuid': cluster_data[self.PRIVATE_NETWORK]}] # Get user_data parameters from metadata jj_vars['KUBETOKEN'] = cluster_data[self.KUBEADM_TOKEN] jj_vars['MASTER_FLOATINGIP'] = cluster_data[ self.KUBE_MASTER_FLOATINGIP] block_device_mapping_v2 = self.properties[self.BLOCK_DEVICE_MAPPING_V2] if block_device_mapping_v2 is not None: kwargs['block_device_mapping_v2'] = self._resolve_bdm( obj, block_device_mapping_v2, 'create') # user_data = self.properties[self.USER_DATA] user_data = base.loadScript('./scripts/master.sh') if user_data is not None: # Use jinja2 to replace variables defined in user_data try: jj_t = jinja2.Template(user_data) user_data = jj_t.render(**jj_vars) except (jinja2.exceptions.UndefinedError, ValueError) as ex: # TODO(anyone) Handle jinja2 error pass ud = encodeutils.safe_encode(user_data) kwargs['user_data'] = encodeutils.safe_decode(base64.b64encode(ud)) sgid = self._get_security_group(obj) kwargs['security_groups'] = [{'name': sgid}] server = None resource_id = None try: server = self.compute(obj).server_create(**kwargs) self.compute(obj).wait_for_server(server.id) server = self.compute(obj).server_get(server.id) self._update_master_ip(obj, server.addresses[''][0]['addr']) self._associate_floatingip(obj, server) LOG.info("Created master node: %s" % server.id) return server.id except exc.InternalError as ex: if server and server.id: resource_id = server.id raise exc.EResourceCreation(type='server', message=six.text_type(ex), resource_id=resource_id)