def _FillInExecutableFromApp(self, wrapper, app): """Fill in the fields of a SandboxSpec.Executable object from |app|. Args: wrapper: instance of SandboxSpecWrapper. app: dictionary of information taken from the appc pod manifest. """ sub_app = json_lib.GetValueOfType( app, KEY_APP_SUB_APP, dict, 'per app app dict') user = json_lib.GetValueOfType( sub_app, KEY_SUB_APP_USER, unicode, 'app dict user') group = json_lib.GetValueOfType( sub_app, KEY_SUB_APP_GROUP, unicode, 'app dict group') if not self._user_db.UserExists(user): raise ValueError('Found invalid username "%s"' % user) if not self._user_db.GroupExists(group): raise ValueError('Found invalid groupname "%s"' % group) cmd = json_lib.GetValueOfType( sub_app, KEY_SUB_APP_EXEC, list, 'app command line') if not cmd: raise ValueError('App command line must give the executable to run.') self._CheckAbsPathToExecutable(cmd[0]) for cmd_piece in cmd: json_lib.AssertIsInstance(cmd_piece, unicode, 'app.exec fragment') port_list = sub_app.get(KEY_SUB_APP_PORTS, None) wrapper.AddExecutable(self._user_db.ResolveUsername(user), self._user_db.ResolveGroupname(group), cmd, _GetPortList(PROTOCOL_TCP, port_list), _GetPortList(PROTOCOL_UDP, port_list), _ExtractLinuxCapNames(sub_app))
def _FillInEndpointNamesFromAnnotations(self, wrapper, annotations): """Fill in the SandboxSpec endpoint_names field from |annotations|. An appc pod specification can contain a list of (mostly) arbitrary annotations that projects can use to add their own metadata fields. |annotations| is a list of dicts that each contain a name and value field, and this method looks for 'name' fields that are prefixed with ENDPOINT_NAME_ANNOTATION_PREFIX and treats the associated 'value' as the name of an endpoint that psyched will expect to be registered from within this sandbox. Args: wrapper: instance of SandboxSpecWrapper. annotations: list of dicts, each with a name and value field. """ for annotation in annotations: json_lib.AssertIsInstance(annotation, dict, 'a single annotation') name = json_lib.GetValueOfType( annotation, KEY_ANNOTATION_NAME, unicode, 'annotation name') if not IsValidAcName(name): raise ValueError('Annotation name "%s" contains illegal characters.' % name) if name.startswith(ENDPOINT_NAME_ANNOTATION_PREFIX): endpoint_name = json_lib.GetValueOfType( annotation, KEY_ANNOTATION_VALUE, unicode, 'endpoint name value') if not IsValidAcName(name): raise ValueError('Endpoint name "%s" contains illegal characters.' % endpoint_name) wrapper.AddEndpointName(endpoint_name)
def GetSandboxSpec(self, appc_contents, sandbox_spec_name): """Create a SandboxSpec encoding the information in an appc pod manifest. Args: appc_contents: string contents of an appc pod manifest sandbox_spec_name: string unique name of this sandbox. Returns: an instance of SandboxSpec. """ wrapper = SandboxSpecWrapper() overlay_name = None app_list = json_lib.GetValueOfType( appc_contents, KEY_APPS_LIST, list, 'app list') for app in app_list: json_lib.AssertIsInstance(app, dict, 'app') # Aid debugging of problems in specific apps. app_name = json_lib.GetValueOfType( app, KEY_APP_NAME, unicode, 'app name') if not IsValidAcName(app_name): raise ValueError('Application name "%s" contains illegal characters.' % app_name) logging.debug('Processing application "%s".', app_name) # Get the name of the image, check that it's consistent other image names. image = json_lib.GetValueOfType( app, KEY_APP_IMAGE, dict, 'image specification for app') image_name = json_lib.GetValueOfType( image, KEY_APP_IMAGE_NAME, unicode, 'image name') if not IsValidAcName(image_name): raise ValueError('Image name "%s" contains illegal characters.' % image_name) if overlay_name and overlay_name != image_name: raise ValueError( 'All elements of "apps" must have the same image.name.') overlay_name = image_name # Add the executable corresponding to this app to our SandboxSpec. self._FillInExecutableFromApp(wrapper, app) if not overlay_name: raise ValueError('Overlays must declare at least one app') annotation_list = json_lib.GetValueOfType( appc_contents, KEY_ANNOTATIONS_LIST, list, 'list of all annotations') self._FillInEndpointNamesFromAnnotations(wrapper, annotation_list) wrapper.SetName(sandbox_spec_name) return wrapper.sandbox_spec
def _ExtractLinuxCapNames(app_dict): """Parses the set of Linux capabilities for an executable. Args: app_dict: dictionary defining an executable. Returns: List of names of Linux capabilities (e.g. ['CAP_CHOWN']). """ if KEY_APP_ISOLATORS not in app_dict: return [] isolator_list = json_lib.GetValueOfType( app_dict, KEY_APP_ISOLATORS, list, 'list of isolators for application') linux_cap_isolators = [] # Look for any isolators related to capability sets. for isolator in isolator_list: json_lib.AssertIsInstance(isolator, dict, 'isolator instance') isolator_name = json_lib.GetValueOfType( isolator, ISOLATOR_KEY_NAME, unicode, 'isolator name') if not isolator_name.startswith(ISOLATOR_NAME_PREFIX): continue if isolator_name != ISOLATOR_NAME_RETAIN_SET: raise ValueError('Capabilities may only be specified as %s' % ISOLATOR_NAME_RETAIN_SET) linux_cap_isolators.append(isolator) # We may have only a single isolator. if len(linux_cap_isolators) > 1: raise ValueError('Found two lists of Linux caps for an executable') if not linux_cap_isolators: return [] value = json_lib.GetValueOfType( linux_cap_isolators[0], ISOLATOR_KEY_VALUE, dict, 'Linux cap isolator value') caps = json_lib.GetValueOfType( value, ISOLATOR_KEY_VALUE_SET, list, 'Linux cap isolator set') for cap in caps: json_lib.AssertIsInstance(cap, unicode, 'Linux capability in set.') return caps
def testPopValueOfType(self): """Test that PopValueOfType is correct.""" input_dict = {'key': 'value'} self.assertEqual( 'value', json_lib.GetValueOfType(input_dict, 'key', str, 'value')) self.assertEqual( 'value', json_lib.PopValueOfType(input_dict, 'key', str, 'value')) self.assertFalse(input_dict)
def testGetValueOfType(self): """Test that GetValueOfType is correct.""" self.assertRaises( ValueError, json_lib.GetValueOfType, {}, 'missing key', str, 'missing value') self.assertRaises( ValueError, json_lib.GetValueOfType, {'key': 1}, 'key', bool, 'bad type') self.assertRaises( ValueError, json_lib.GetValueOfType, {'key': [1]}, 'key', int, 'bad type') self.assertEqual( json_lib.GetValueOfType({'key': 1}, 'key', int, 'good value'), 1)