def AddAccountsFromDatabase(self, account_db_path): """Add accounts from the database at |account_db_path| to self. Overrides previously loaded accounts. Args: account_db_path: path to file containing an account database. """ raw_db = json_lib.ParseJsonFileWithComments(account_db_path) json_lib.AssertIsInstance(raw_db, dict, 'accounts database') # We don't mandate that an accounts database specify either field. raw_db.setdefault(USERS_KEY, []) raw_db.setdefault(GROUPS_KEY, []) user_list = json_lib.PopValueOfType(raw_db, USERS_KEY, list, 'list of users in accounts database') group_list = json_lib.PopValueOfType(raw_db, GROUPS_KEY, list, 'list of groups in accounts database') # We do mandate that the database contain only fields we know about. if raw_db: raise ValueError('Accounts database include unknown fields: %r' % raw_db.keys()) for user in user_list: json_lib.AssertIsInstance( user, dict, 'user specification in accounts database') self._AddUser(user) for group in group_list: json_lib.AssertIsInstance( group, dict, 'group specification in accounts database') self._AddGroup(group)
def _AddUser(self, user_spec): """Add a user to this account database based on |user_spec|. Args: user_spec: dict of information from an accounts database. This fragment is expected to have been parsed from developer supplied JSON and will be type checked. """ # By default, user accounts are locked and cannot be logged into. user_spec.setdefault(USER_PASSWORD_KEY, u'!') # By default, users don't get a shell. user_spec.setdefault(USER_SHELL_KEY, u'/bin/false') # By default, users don't get a home directory. user_spec.setdefault(USER_HOME_KEY, u'/dev/null') # By default, users don't get a fixed UID. user_spec.setdefault(USER_FIXED_ID_KEY, False) # By default, users don't need a comment. user_spec.setdefault(USER_COMMENT_KEY, u'') # By default, users are not defunct. user_spec.setdefault(USER_DEFUNCT_KEY, False) name = json_lib.PopValueOfType(user_spec, USER_NAME_KEY, six.text_type, 'username from user spec') password = json_lib.PopValueOfType(user_spec, USER_PASSWORD_KEY, six.string_types, 'password for user %s' % name) uid = json_lib.PopValueOfType(user_spec, USER_ID_KEY, int, 'default uid for user %s' % name) group_name = json_lib.PopValueOfType( user_spec, USER_GROUP_KEY, six.text_type, 'primary group for user %s' % name) description = json_lib.PopValueOfType(user_spec, USER_COMMENT_KEY, six.text_type, 'description for user %s' % name) home = json_lib.PopValueOfType(user_spec, USER_HOME_KEY, six.text_type, 'home directory for user %s' % name) shell = json_lib.PopValueOfType(user_spec, USER_SHELL_KEY, six.text_type, 'shell for user %s' % name) is_fixed_id = json_lib.PopValueOfType( user_spec, USER_FIXED_ID_KEY, bool, 'whether UID for user %s is fixed' % name) is_defunct = json_lib.PopValueOfType( user_spec, USER_DEFUNCT_KEY, bool, 'whether user %s is defunct.' % name) if user_spec: raise ValueError('Unexpected keys in user spec for user %s: %r' % (name, user_spec.keys())) self.users[name] = User(name=name, password=password, uid=uid, group_name=group_name, description=description, home=home, shell=shell, is_fixed_id=is_fixed_id, is_defunct=is_defunct)
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 _AddGroup(self, group_spec): """Add a group to this account database based on |group_spec|. Args: group_spec: dict of information from an accounts database. This fragment is expected to have been parsed from developer supplied JSON and will be type checked. """ # By default, groups don't get a fixed GID. group_spec.setdefault(GROUP_FIXED_ID_KEY, False) # By default, groups don't get a password. group_spec.setdefault(GROUP_PASSWORD_KEY, u'!') # By default, groups are not defunct. group_spec.setdefault(GROUP_DEFUNCT_KEY, False) name = json_lib.PopValueOfType(group_spec, GROUP_NAME_KEY, six.text_type, 'groupname from group spec') password = json_lib.PopValueOfType(group_spec, GROUP_PASSWORD_KEY, six.text_type, 'password for group %s' % name) gid = json_lib.PopValueOfType(group_spec, GROUP_ID_KEY, int, 'gid for group %s' % name) users = json_lib.PopValueOfType(group_spec, GROUP_USERS_KEY, list, 'users in group %s' % name) is_fixed_id = json_lib.PopValueOfType( group_spec, GROUP_FIXED_ID_KEY, bool, 'whether GID for group %s is fixed' % name) is_defunct = json_lib.PopValueOfType( group_spec, GROUP_DEFUNCT_KEY, bool, 'whether group %s is defunct' % name) for username in users: json_lib.AssertIsInstance(username, six.text_type, 'user in group %s' % name) if group_spec: raise ValueError('Unexpected keys in group spec for group %s: %r' % (name, group_spec.keys())) self.groups[name] = Group(name=name, password=password, gid=gid, users=users, is_fixed_id=is_fixed_id, is_defunct=is_defunct)
def _GetPortList(desired_protocol, appc_port_list): """Get the list of ports opened for |desired_protocol| from |appc_port_list|. Args: desired_protocol: one of VALID_PROTOCOLS. appc_port_list: list of port specifications from a appc pod manifest. Returns: Instance of PortSpec. """ # The port specification is optional. if appc_port_list is None: return PortSpec(False, []) json_lib.AssertIsInstance(appc_port_list, list, 'port specification list') allow_all = False port_list = [] for port_dict in appc_port_list: json_lib.AssertIsInstance(port_dict, dict, 'port specification') port_dict = copy.deepcopy(port_dict) # By default, we open a single specified port. port_dict.setdefault(PORT_SPEC_COUNT, 1) # By default, don't set socket activated. port_dict.setdefault(PORT_SPEC_SOCKET_ACTIVATED, False) # We don't actually use the port name, but it's handy for documentation # and standard adherence to enforce its existence. port_name = json_lib.PopValueOfType( port_dict, PORT_SPEC_NAME, unicode, 'port name') logging.debug('Validating appc specifcation of "%s"', port_name) port = json_lib.PopValueOfType(port_dict, PORT_SPEC_PORT, int, 'port') protocol = json_lib.PopValueOfType( port_dict, PORT_SPEC_PROTOCOL, unicode, 'protocol') count = json_lib.PopValueOfType( port_dict, PORT_SPEC_COUNT, int, 'port range count') # We also don't use the socketActivated flag, but we should tolerate safe # values. socket_activated = json_lib.PopValueOfType( port_dict, PORT_SPEC_SOCKET_ACTIVATED, bool, 'socket activated flag') # Validate everything before acting on it. if protocol not in VALID_PROTOCOLS: raise ValueError('Port protocol must be in %r, not "%s"' % (VALID_PROTOCOLS, protocol)) if protocol != desired_protocol: continue if socket_activated != False: raise ValueError('No support for socketActivated==True in %s' % port_name) if port_dict: raise ValueError('Unknown keys found in port spec %s: %r' % (port_name, port_dict.keys())) if port == -1: # Remember that we're going to return that all ports are opened, but # continue validating all the remaining specifications. allow_all = True continue # Now we know it's not the wildcard port, and that we've never declared # a wildcard for this protocol. port = remote_access.NormalizePort(port) if count < 1: raise ValueError('May only specify positive port ranges for %s' % port_name) if port + count >= 65536: raise ValueError('Port range extends past max port number for %s' % port_name) for effective_port in xrange(port, port + count): port_list.append(effective_port) return PortSpec(allow_all, port_list)