def __init__(self, cli_args, config_dir): """ Run the action. """ self._args = cli_args self._config_dir = config_dir self._config = ConfigurationFactory.get('hypernova') self._servers = ConfigurationFactory.get('hypernova.servers')
def do_rm_record(params): """ Remove a record. """ config = ConfigurationFactory.get('hypernova') server = get_authoritative_server(config['dns']['adapter'], config['dns']) result = {'records': []} try: zone = server.get_zone(params['zone']) params['rtype'] = params['record'].pop('type') records = zone.filter_records_for(params['record']) for r in records: result['records'].append(r.to_encodable()) server.rm_record(zone, r) successful = True if len(result['records']) == 0: successful = False result['error'] = 'NoMatchingRecords' except NonexistentZoneError: successful = False result = {'error': 'NonexistentZoneError'} return AgentRequestHandler._format_response( result, successful=successful )
def do_add_record(params): """ Add a record to an existing zone. """ config = ConfigurationFactory.get('hypernova') server = get_authoritative_server(config['dns']['adapter'], config['dns']) try: zone = server.get_zone(params['zone']) record = Record(params['record']['name'], params['record']['type'], params['record']['content'], params['record']['ttl'], params['record']['priority']) server.add_record(zone, record) successful = True result = {'record': record.to_encodable()} except NonexistentZoneError: successful = False result = {'error': 'NonexistentZone'} return AgentRequestHandler._format_response( result, successful=successful )
def do_get_zone(params): """ Get a zone. """ config = ConfigurationFactory.get('hypernova') try: server = get_authoritative_server(config['dns']['adapter'], config['dns']) try: successful = True result = { 'zone': server.get_zone(params['domain']).to_encodable(), } except NonexistentZoneError: successful = False result = {'error': 'NonexistentZone'} except ServerCommunicationError: successful = False result = {'error': 'ServerCommunication'} return AgentRequestHandler._format_response( result, successful=successful, error_code=0 )
def elevate_cmd(cmd): """ Return an elevated command, ready for execution. When cmd is a list, we prepend the options necessary for the command to run as the system's root/administrative user as seperate, self-contained arguments. When it's a string, we prepend to the string the space-delimited parameters. If the object is of any other type, a TypeError will be thrown. """ try: config = ConfigurationFactory.get('hypernova')['elevation'] if config['method'] == 'elevator': prefix = [config['binary']] except KeyError: prefix = None finally: if not prefix: return cmd if isinstance(cmd, list): prefix.extend(cmd) cmd = prefix elif isinstance(cmd, str): cmd = '%s %s' %(' '.join(prefix), cmd) else: raise TypeError('list or str expected') return cmd
def _init_config(self): """ Load the client's configuration. """ self._config_file = os.path.join(self._config_dir, 'client.ini') self._servers_file = os.path.join(self._config_dir, 'servers.ini') try: os.listdir(self._config_dir) except (LoadError, OSError): print('Creating configuration in %s' %(self._config_dir), file=sys.stderr) self._init_config_runonce(self._config_dir) finally: self._config = ConfigurationFactory.get('hypernova', root_dir=self._config_file) self._servers = ConfigurationFactory.get('hypernova.servers', root_dir=self._servers_file)
def _init_config(self, config_root_dir): """ Initialise configuration values. See __init__() for more information. """ self._main_log.info('loading configuration from directory %s' %(config_root_dir)) self._config = ConfigurationFactory.get('hypernova', config_root_dir, self._main_log) if not self._config: self._main_log.critical('loading configuration failed') sys.exit(78)
def __init__(self, **args): """ Initialise the provisioner. """ self.parameters = args config = ConfigurationFactory.get('hypernova') # This will only be possible when in the context of the agent, so if we # fail, it's not an issue. This ought to be cleaned up. try: self._base_cmd.append(config['provisioner']['config_dir']) except KeyError: pass
def get_package_db(pdb_name=None): """ Get the system's associated package DB. """ prof_dir = ConfigurationFactory.get('hypernova')['platforms']['profile_dir'] pdb_fmt = os.path.join(prof_dir, '%s', 'packages.json') if not pdb_name: os_info = platform.dist() if os_info[0].lower() in ('centos', 'fedora'): pdb_name = 'rhel-6' return PackageDB(pdb_fmt %(pdb_name))
def __init__(self, *args): """ Initialise the provisioner. """ self.parameters = args self.config = ConfigurationFactory.get('hypernova') self.env = deepcopy(environ) # Attempt to guess the provsioner's configuration directory; we can only # do this if it's set in the agent's configuration try: self.env['CONFDIR'] = self.config['provisioner']['config_dir'] except KeyError: pass
def do_add_zone(params): """ Add a zone. """ config = ConfigurationFactory.get('hypernova') try: result = {'error': 'ValidationError'} server = get_authoritative_server(config['dns']['adapter'], config['dns']) zone = Zone(new_domain=params['zone']['domain'], new_origin=params['zone']['origin'], new_ttl=params['zone']['ttl']) zone.soa_record = SoaRecord(new_primary_ns=params['soa']['primary_ns'], new_responsible_person=params['soa']['responsible_person'], new_serial=params['soa']['serial'], new_refresh=params['soa']['refresh'], new_retry=params['soa']['retry'], new_expire=params['soa']['expire'], new_min_ttl=params['soa']['min_ttl']) try: server.add_zone(zone) successful = True result = {'zone': zone.to_encodable()} except DuplicateZoneError: successful = False result = {'error': 'DuplicateZone'} except ServerCommunicationError: successful = False result = {'error': 'ServerCommunicationError'} return AgentRequestHandler._format_response( result, successful=successful, error_code=0 )
def setUp(self): """ Construct environment. Here, we adopt the configuration used by the production or development installation and make the necessary changes before writing it to a new file in the etc directory. When we're finished, we'll remove it in the tearDown() function. """ if not os.path.exists(self.client_env['CONFDIR']): # Don't waste time and entropy on keys if we can't write configuration # files -- that's a very distressing experience. assert len(sys.argv) == 2 # Prepare two GPG keypairs; one for the agent, one for the client agent_gpg_dir = os.path.join(self.client_env['CONFDIR'], 'agent_gpg') agent_gpg = GPG(gnupghome=agent_gpg_dir) agent_key = agent_gpg.gen_key(agent_gpg.gen_key_input(**self.gpg_params)) client_gpg_dir = os.path.join(self.client_env['CONFDIR'], 'client_gpg') client_gpg = GPG(gnupghome=client_gpg_dir) client_key = client_gpg.gen_key(client_gpg.gen_key_input(**self.gpg_params)) # Export both public keys; import them into the opposing side agent_key_blob = agent_gpg.export_keys(agent_key.fingerprint) client_gpg.import_keys(agent_key_blob) client_gpg.sign_key(agent_key.fingerprint) client_key_blob = client_gpg.export_keys(client_key.fingerprint) agent_gpg.import_keys(client_key_blob) agent_gpg.sign_key(client_key.fingerprint) # Configure the agent to run in a development-safe configuration. # # Here, we load the base configuration we ship with the application # as the default. All other configuration will be ignored for the # purposes of the test run, since this is outside of our scope. with open(self.agent_env['CONFDIR'], 'w') as f: l = os.path.join(self.client_env['CONFDIR'], 'agent_%s.log') agent_cfg = ConfigurationFactory.get('hypernova.agent', root_dir=sys.argv[1]) agent_cfg.set('server', 'address', self.agent_addr[0]) agent_cfg.set('server', 'port', self.agent_addr[1]) agent_cfg.set('server', 'daemon', 'false') agent_cfg.set('gpg', 'key_store', agent_gpg_dir) agent_cfg.set('gpg', 'fingerprint', agent_key.fingerprint) agent_cfg.set('logging', 'main_log', l %('main')) agent_cfg.set('logging', 'request_log', l %('request')) agent_cfg.set('logging', 'error_log', l %('error')) agent_cfg.write(f) # The client has to use two different configuration files, both in # the same directory. client_cfg_dir = self.client_env['CONFDIR'] # Configure the client to use its temporary key. # # To communicate with the agent (which will be running in a limited # testing mode), we'll need to reconfigure the client with a keypair # we've imported into the agent. This keystore manipulation has # already taken place, so we know the fingerprint of our new private # key. client_cfg_file = os.path.join(client_cfg_dir, 'client.ini') with open(client_cfg_file, 'w') as f: client_cfg = configparser.SafeConfigParser() client_cfg.add_section('client') client_cfg.set('client', 'privkey', client_key.fingerprint) client_cfg.write(f) # Pair the client to the agent. # # We do this manually, since the importer requires that we write the # public key to a file before we import it. This would be a # pointless exercise and an unnecessary complication. client_srv_file = os.path.join(client_cfg_dir, 'servers.ini') with open(client_srv_file, 'w') as f: client_srv_cfg = configparser.SafeConfigParser() client_srv_cfg.add_section('local') client_srv_cfg.set('local', 'addr', ':'.join(self.agent_addr)) client_srv_cfg.set('local', 'pubkey', agent_key.fingerprint) client_srv_cfg.write(f) # TODO: instead of lazily and unreliably falling asleep on the job, # we should probably use a regular expression to check the output. # Time is of the essence, though! # No, we'll use pexpect instead, since it's now shipped as a py3k # dependency. agent_cmd = [ 'hn-agent', self.agent_env['CONFDIR'] ] self.agent_proc = subprocess.Popen(agent_cmd, env=self.agent_env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) time.sleep(self.agent_init_time)