def sync(verbose=False): ignore_devices_on_servers_re = None if config.has_option('inventory', 'ignore_devices_on_servers_re'): ignore_devices_on_servers_re = config.get('inventory', 'ignore_devices_on_servers_re') from_inv = get_devices( config.get('inventory', 'url'), config.get('inventory', 'filter'), config.get('inventory', 'username'), config.get('inventory', 'password'), ignore_devices_on_servers_re, verbose=verbose) # dump the db second, since otherwise the mysql server can go away while # get_devices is still running, which is no fun from_db = data.dump_devices() for task in merge_devices(from_db, from_inv): if task[0] == 'insert': if verbose: print "insert device", task[1]['fqdn'] data.insert_device(task[1]) elif task[0] == 'delete': if verbose: print "delete device", task[2] data.delete_device(task[1]) elif task[0] == 'update': if verbose: print "update device", task[2] data.update_device(task[1], task[2]) else: raise AssertionError('%s is not a task' % task[0])
def sync(db, verbose=False, ship_it=False): ignore_devices_on_servers_re = None if config.has_option('inventory', 'ignore_devices_on_servers_re'): ignore_devices_on_servers_re = config.get('inventory', 'ignore_devices_on_servers_re') from_inv = get_devices( config.get('inventory', 'url'), config.get('inventory', 'filter'), config.get('inventory', 'username'), config.get('inventory', 'password'), ignore_devices_on_servers_re, verbose=verbose) # dump the db second, since otherwise the mysql server can go away while # get_devices is still running, which is no fun from_db = db.inventorysync.dump_devices() ## get a list of relay_boards derived from the inventory dump relay_boards_from_inv = get_relay_boards(from_inv) ## get existing relay_board list from DB relay_boards_from_db = db.inventorysync.dump_relays() # get the list of changes that need to be made tasks = list(merge_devices(from_db, from_inv)) # If there are too many changes, bail out and await human interaction. # "Too many" means more than 5 and more than a tenth of the larger of the # set of devices currently in inventory and the set in the DB. This is a # failsafe to keep the inventory sync from unexpectedly erasing all # devices. if len(tasks) > max(5, len(from_db) / 10, len(from_inv) / 10) and not ship_it: raise RuntimeError("%d changes: pass --ship-it to make these changes" % len(tasks)) # start merging devices for task in tasks: if task[0] == 'insert': if verbose: print "insert device", task[1]['fqdn'] db.inventorysync.insert_device(task[1]) elif task[0] == 'delete': if verbose: print "delete device", task[2] db.inventorysync.delete_device(task[1]) elif task[0] == 'update': if verbose: print "update device", task[2] db.inventorysync.update_device(task[1], task[2]) else: raise RuntimeError('%s is not a task' % task[0]) # start merging relay_boards for task in merge_relay_boards(relay_boards_from_db, relay_boards_from_inv): if task[0] == 'insert': if verbose: print "insert relay_board", task[1]['fqdn'] db.inventorysync.insert_relay_board(task[1]) elif task[0] == 'delete': if verbose: print "delete relay_board", task[2] db.inventorysync.delete_relay_board(task[1]) elif task[0] == 'update': if verbose: print "update relay_board", task[2] db.inventorysync.update_relay_board(task[1], task[2]) else: raise RuntimeError('%s is not a task' % task[0])
def POST(self, device_name): args, body = templeton.handlers.get_request_parms() try: assignee = body['assignee'] duration = int(body['duration']) image_name = body['image'] environment = body.get('environment', 'any') except (KeyError, ValueError): raise web.badrequest() try: image = self.db.images.get(image_name) except exceptions.NotFound: raise web.notfound() boot_config = {} for k in image['boot_config_keys']: try: boot_config[k] = body[k] except KeyError: raise web.badrequest() request_id = self.db.requests.add(device_name, environment, assignee, duration, image['id'], boot_config) mozpool.mozpool.driver.handle_event(request_id, 'find_device', None) info = self.db.requests.get_info(request_id) info['url'] = "http://%s/api/request/%d/" % ((config.get('server', 'fqdn'), request_id)) response_data = {'request': info} if self.db.requests.get_machine_state(request_id) == 'closed': raise ConflictJSON(response_data) return response_data
def request_config(request_id): conn = sql.get_conn() res = conn.execute( select( [ model.requests.c.requested_device, model.requests.c.assignee, model.requests.c.expires, model.requests.c.boot_config, ], model.requests.c.id == request_id, ) ) row = res.fetchone() if row is None: raise NotFound request = { "id": request_id, "requested_device": row[0].encode("utf-8"), "assignee": row[1].encode("utf-8"), "expires": row[2].isoformat(), "boot_config": row[3].encode("utf-8"), "assigned_device": "", "url": "http://%s/api/request/%d/" % (config.get("server", "fqdn"), request_id), } assigned_device = get_assigned_device(request_id) if assigned_device: request["assigned_device"] = assigned_device return request
def create_request(requested_device, assignee, duration, boot_config): conn = sql.get_conn() server_id = conn.execute( select([model.imaging_servers.c.id], model.imaging_servers.c.fqdn == config.get( 'server', 'fqdn'))).fetchall()[0][0] reservation = { 'imaging_server_id': server_id, 'requested_device': requested_device, 'assignee': assignee, 'expires': datetime.datetime.utcnow() + datetime.timedelta(seconds=duration), 'boot_config': json.dumps(boot_config), 'state': 'new', 'state_counters': '{}' } res = conn.execute(model.requests.insert(), reservation) return res.lastrowid
def main(): # templeton uses $PWD/../html to serve /, so put PWD in a subdirectory of # the directory containing our html data. Easiest is to just change the the # html directory itself os.chdir(os.path.join(os.path.dirname(mozpool.__file__), 'html')) # Set up logging logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format="%(name)s %(levelname)s - [%(asctime)s] %(message)s") # ignore urllib3 informational logging urllib3_logger = logging.getLogger('requests.packages.urllib3') urllib3_logger.setLevel(logging.CRITICAL) # if we're running fake boards, start those up if config.get('testing', 'run_fakes'): from mozpool.test import fakedevices rack = fakedevices.Rack() rack.start() # start up the lifeguard driver # TODO: make this configurable, as well as poll freq mozpool.lifeguard.driver = devicemachine.LifeguardDriver() mozpool.lifeguard.driver.start() # start up the mozpool driver mozpool.mozpool.driver = requestmachine.MozpoolDriver() mozpool.mozpool.driver.start() app = get_app() app.run()
def request_config(request_id): conn = sql.get_conn() res = conn.execute( select([ model.requests.c.requested_device, model.requests.c.assignee, model.requests.c.expires, model.requests.c.boot_config ], model.requests.c.id == request_id)) row = res.fetchone() if row is None: raise NotFound request = { 'id': request_id, 'requested_device': row[0].encode('utf-8'), 'assignee': row[1].encode('utf-8'), 'expires': row[2].isoformat(), 'boot_config': row[3].encode('utf-8'), 'assigned_device': '', 'url': 'http://%s/api/request/%d/' % (config.get('server', 'fqdn'), request_id) } assigned_device = get_assigned_device(request_id) if assigned_device: request['assigned_device'] = assigned_device return request
def _send_event(self, event, set_state=True): # conveniently, most state and event names match if set_state: self._set_state(event) fqdn = config.get('server', 'fqdn') url = 'http://%s/api/device/%s/event/%s/' % (fqdn, self.name, event) requests.get(url)
def request_config(request_id): conn = sql.get_conn() res = conn.execute(select([model.requests.c.requested_device, model.requests.c.assignee, model.requests.c.expires, model.requests.c.environment, model.images.c.name.label('image'), model.requests.c.boot_config], model.requests.c.id==request_id, from_obj=[model.requests.join(model.images)])) row = res.fetchone() if row is None: raise NotFound request = {'id': request_id, 'requested_device': row[0].encode('utf-8'), 'assignee': row[1].encode('utf-8'), 'expires': row[2].isoformat(), 'environment': row[3].encode('utf-8'), 'image': row[4].encode('utf-8'), 'boot_config': row[5].encode('utf-8'), 'assigned_device': '', 'url': 'http://%s/api/request/%d/' % (config.get('server', 'fqdn'), request_id)} assigned_device = get_assigned_device(request_id) if assigned_device: request['assigned_device'] = assigned_device return request
def contact_lifeguard(self): device_request_data = {} request_config = data.request_config(self.machine.request_id) # Determine if we are imaging or just rebooting. # We need to pass boot_config as a JSON string, but verify that it's # a non-null object. if json.loads(request_config['boot_config']): event = 'please_pxe_boot' device_request_data['boot_config'] = request_config['boot_config'] # FIXME: differentiate between b2g builds and other (future) image # types. device_request_data['pxe_config'] = config.get('mozpool', 'b2g_pxe_config') else: event = 'please_power_cycle' device_url = 'http://%s/api/device/%s/event/%s/' % ( data.get_server_for_device(request_config['assigned_device']), request_config['assigned_device'], event) # FIXME: make this asynchronous so slow/missing servers don't halt # the state machine. try: urllib.urlopen(device_url, json.dumps(device_request_data)) except IOError: logs.request_logs.add(self.machine.request_id, "could not contact lifeguard server at %s" % device_url) return False return True
def contact_lifeguard(self): device_request_data = {} request_config = data.request_config(self.machine.request_id) # Determine if we are imaging or just rebooting. # We need to pass boot_config as a JSON string, but verify that it's # a non-null object. if json.loads(request_config['boot_config']): event = 'please_pxe_boot' device_request_data['boot_config'] = request_config['boot_config'] # FIXME: differentiate between b2g builds and other (future) image # types. device_request_data['pxe_config'] = config.get( 'mozpool', 'b2g_pxe_config') else: event = 'please_power_cycle' device_url = 'http://%s/api/device/%s/event/%s/' % ( data.get_server_for_device(request_config['assigned_device']), request_config['assigned_device'], event) # FIXME: make this asynchronous so slow/missing servers don't halt # the state machine. try: urllib.urlopen(device_url, json.dumps(device_request_data)) except IOError: logs.request_logs.add( self.machine.request_id, "could not contact lifeguard server at %s" % device_url) return False return True
def add(self, requested_device, environment, assignee, duration, image_id, boot_config, _now=datetime.datetime.utcnow): """ Add a new request with the given parameters. The state is set to 'new'. Returns the ID of the new request. """ server_id = self.db.execute( select([model.imaging_servers.c.id], model.imaging_servers.c.fqdn == config.get( 'server', 'fqdn'))).fetchall()[0][0] request = { 'imaging_server_id': server_id, 'requested_device': requested_device, 'environment': environment, 'assignee': assignee, 'expires': _now() + datetime.timedelta(seconds=duration), 'image_id': image_id, 'boot_config': json.dumps(boot_config), 'state': 'new', 'state_counters': '{}' } res = self.db.execute(model.requests.insert(), request) return res.lastrowid
def POST(self, device_name): args, body = templeton.handlers.get_request_parms() try: assignee = body['assignee'] duration = int(body['duration']) image_name = body['image'] environment = body.get('environment', 'any') except (KeyError, ValueError): raise web.badrequest() try: image = self.db.images.get(image_name) except exceptions.NotFound: raise web.notfound() boot_config = {} for k in image['boot_config_keys']: try: boot_config[k] = body[k] except KeyError: raise web.badrequest() request_id = self.db.requests.add(device_name, environment, assignee, duration, image['id'], boot_config) mozpool.mozpool.driver.handle_event(request_id, 'find_device', None) info = self.db.requests.get_info(request_id) info['url'] = "http://%s/api/request/%d/" % ( (config.get('server', 'fqdn'), request_id)) response_data = {'request': info} if self.db.requests.get_machine_state(request_id) == 'closed': raise ConflictJSON(response_data) return response_data
def sync(db, verbose=False): ignore_devices_on_servers_re = None if config.has_option('inventory', 'ignore_devices_on_servers_re'): ignore_devices_on_servers_re = config.get('inventory', 'ignore_devices_on_servers_re') from_inv = get_devices( config.get('inventory', 'url'), config.get('inventory', 'filter'), config.get('inventory', 'username'), config.get('inventory', 'password'), ignore_devices_on_servers_re, verbose=verbose) # dump the db second, since otherwise the mysql server can go away while # get_devices is still running, which is no fun from_db = db.inventorysync.dump_devices() ## get a list of relay_boards derived from the inventory dump relay_boards_from_inv = get_relay_boards(from_inv) ## get existing relay_board list from DB relay_boards_from_db = db.inventorysync.dump_relays() # start merging devices for task in merge_devices(from_db, from_inv): if task[0] == 'insert': if verbose: print "insert device", task[1]['fqdn'] db.inventorysync.insert_device(task[1]) elif task[0] == 'delete': if verbose: print "delete device", task[2] db.inventorysync.delete_device(task[1]) elif task[0] == 'update': if verbose: print "update device", task[2] db.inventorysync.update_device(task[1], task[2]) else: raise RuntimeError('%s is not a task' % task[0]) # start merging relay_boards for task in merge_relay_boards(relay_boards_from_db, relay_boards_from_inv): if task[0] == 'insert': if verbose: print "insert relay_board", task[1]['fqdn'] db.inventorysync.insert_relay_board(task[1]) elif task[0] == 'delete': if verbose: print "delete relay_board", task[2] db.inventorysync.delete_relay_board(task[1]) elif task[0] == 'update': if verbose: print "update relay_board", task[2] db.inventorysync.update_relay_board(task[1], task[2]) else: raise RuntimeError('%s is not a task' % task[0])
def wrapped(self, id, *args): try: server = data.get_server_for_request(id) except data.NotFound: raise web.notfound() if server != config.get('server', 'fqdn'): raise web.found("http://%s%s" % (server, web.ctx.path)) return function(self, id, *args)
def _get_device_config_path(device_name): """ Get the path where the PXE boot symlink should be placed for a specific device. """ mac_address = data.mac_with_dashes(data.device_mac_address(device_name)) symlink_dir = os.path.join(config.get('paths', 'tftp_root'), "pxelinux.cfg") return os.path.join(symlink_dir, "01-" + mac_address)
def wrapped(self, id, *args): try: server = self.db.relay_boards.get_imaging_server(id) except exceptions.NotFound: raise web.notfound() if server != config.get('server', 'fqdn'): raise web.found("http://%s%s" % (server, web.ctx.path)) return function(self, id, *args)
def _get_device_config_path(mac_address): """ Get the path where the PXE boot symlink should be placed for a specific device. """ mac_address = util.mac_with_dashes(mac_address) symlink_dir = os.path.join(config.get('paths', 'tftp_root'), "pxelinux.cfg") return os.path.join(symlink_dir, "01-" + mac_address)
def test_load(self, gethostbyname, getfqdn): getfqdn.return_value = 'server.example.com' gethostbyname.return_value = '1.2.3.4' cfg_file = os.path.join(self.tempdir, "cfg") open(cfg_file, "w").write(textwrap.dedent("""\ [test] val1 = 1 """)) os.environ['MOZPOOL_CONFIG'] = cfg_file config._config = None config._load() # check defaults as well as the value in the config above self.assertEqual(config.get('server', 'fqdn'), 'server.example.com') self.assertEqual(config.get('server', 'ipaddress'), '1.2.3.4') self.assertEqual(config.get('test', 'val1'), '1')
def GET(self, request_id): try: request_id = int(request_id) info = self.db.requests.get_info(request_id) info['url'] = "http://%s/api/request/%d/" % ((config.get('server', 'fqdn'), request_id)) return info except ValueError: raise web.badrequest() except exceptions.NotFound: raise web.notfound()
def GET(self, request_id): try: request_id = int(request_id) info = self.db.requests.get_info(request_id) info['url'] = "http://%s/api/request/%d/" % ( (config.get('server', 'fqdn'), request_id)) return info except ValueError: raise web.badrequest() except exceptions.NotFound: raise web.notfound()
def setUp(self): super(TestDevicePing, self).setUp() add_server("server1") self.device_mac = "001122334455" add_device("device1", server="server1", state="running", mac_address=self.device_mac, relayinfo="relay-1:bank1:relay1") self.pxefile = "image1" # create a file for the boot image. open(os.path.join(config.get('paths', 'image_store'), self.pxefile), "w").write("abc") add_pxe_config("image1")
def wrapped(self, id, *args): try: server = data.get_server_for_device(id) except data.NotFound: raise web.notfound() if server != config.get('server', 'fqdn'): raise web.found("http://%s%s" % (server, web.ctx.path)) # otherwise, send an access-control header, so that pages in other domains can # call this API endpoint without trouble fqdns = data.all_imaging_servers() origins = [ 'http://%s' % fqdn for fqdn in fqdns ] web.header('Access-Control-Allow-Origin', ' '.join(origins)) return function(self, id, *args)
def _get_second_stage(self): mac_address = data.mac_with_dashes(data.device_mac_address(self.name)) dir = os.path.join(config.get('paths', 'tftp_root'), "pxelinux.cfg") filename = os.path.join(dir, "01-" + mac_address) if os.path.exists(filename): with open(filename) as f: cfg = f.read() mo = re.search('mobile-imaging-url=[^ ]*/([^ ]*).sh', cfg) if mo: return mo.group(1) else: self.logger.warn('PXE config does not contain a mobile-imaging-url; not PXE booting') # if nothing's found, return None return None
def set_pxe(mac_address, pxe_config): """ Set up the PXE configuration for the device as directed, substituting the server's IP address. Note that this does *not* reboot the device. """ # Write out the config file device_config_path = _get_device_config_path(mac_address) device_config_dir = os.path.dirname(device_config_path) if not os.path.exists(device_config_dir): os.makedirs(device_config_dir) # apply ipaddress substitution to the config contents pxe_config_contents = pxe_config.replace('%IPADDRESS%', config.get('server', 'ipaddress')) open(device_config_path, "w").write(pxe_config_contents)
def wrapped(self, id, *args): try: server = self.db.devices.get_imaging_server(id) except exceptions.NotFound: raise web.notfound() if server != config.get('server', 'fqdn'): raise web.found("http://%s%s" % (server, web.ctx.path)) # send an appropriate access-control header, if necessary origin = web.ctx.environ.get('HTTP_ORIGIN') if origin and origin.startswith('http://'): origin_hostname = origin[7:] fqdns = self.db.imaging_servers.list() if origin_hostname not in fqdns: raise web.Forbidden web.header('Access-Control-Allow-Origin', origin) return function(self, id, *args)
def _get_second_stage(self): mac_address = util.mac_with_dashes( self.db.devices.get_mac_address(self.name)) dir = os.path.join(config.get('paths', 'tftp_root'), "pxelinux.cfg") filename = os.path.join(dir, "01-" + mac_address) if os.path.exists(filename): with open(filename) as f: cfg = f.read() mo = re.search('mobile-imaging-url=[^ ]*/([^ ]*).sh', cfg) if mo: return mo.group(1) else: self.logger.warn( 'PXE config does not contain a mobile-imaging-url; not PXE booting' ) # if nothing's found, return None return None
def create_request(requested_device, assignee, duration, boot_config): conn = sql.get_conn() server_id = conn.execute( select([model.imaging_servers.c.id], model.imaging_servers.c.fqdn == config.get("server", "fqdn")) ).fetchall()[0][0] reservation = { "imaging_server_id": server_id, "requested_device": requested_device, "assignee": assignee, "expires": datetime.datetime.utcnow() + datetime.timedelta(seconds=duration), "boot_config": json.dumps(boot_config), "state": "new", "state_counters": "{}", } res = conn.execute(model.requests.insert(), reservation) return res.lastrowid
def set_pxe(device_name, pxe_config_name, boot_config): """ Set up the PXE configuration for the device as directed. Note that this does *not* reboot the device. """ logger.info('setting pxe config for %s to %s%s' % (device_name, pxe_config_name, ' with boot config' if boot_config else '')) image_details = data.pxe_config_details(pxe_config_name)['details'] pxe_config_contents = image_details['contents'] # Write out the config file device_config_path = _get_device_config_path(device_name) device_config_dir = os.path.dirname(device_config_path) if not os.path.exists(device_config_dir): os.makedirs(device_config_dir) # apply ipaddress substitution to the config contents pxe_config_contents = pxe_config_contents.replace('%IPADDRESS%', config.get('server', 'ipaddress')) open(device_config_path, "w").write(pxe_config_contents)
def _populate(self): fqdn = config.get('server', 'fqdn') for dev_dict in self.db.devices.list(detail=True): # only emulate devices managed by this imaging sever if dev_dict['imaging_server'] != fqdn: continue # only emulate devices with relay info starting with 'localhost' hostname, bank, relay = dev_dict['relay_info'].rsplit(":", 2) if not hostname.startswith('localhost:'): continue if hostname not in self.chassis: self.chassis[hostname] = Chassis(self, hostname) chassis = self.chassis[hostname] device = Device(self, dev_dict['name'], dev_dict) self.devices[dev_dict['name']] = device self.devices_by_fqdn[dev_dict['fqdn']] = device chassis.add_device(int(bank[4:]), int(relay[5:]), device)
def create_request(requested_device, environment, assignee, duration, image_id, boot_config): conn = sql.get_conn() server_id = conn.execute(select( [model.imaging_servers.c.id], model.imaging_servers.c.fqdn==config.get('server', 'fqdn')) ).fetchall()[0][0] reservation = {'imaging_server_id': server_id, 'requested_device': requested_device, 'environment': environment, 'assignee': assignee, 'expires': datetime.datetime.utcnow() + datetime.timedelta(seconds=duration), 'image_id': image_id, 'boot_config': json.dumps(boot_config), 'state': 'new', 'state_counters': '{}'} res = conn.execute(model.requests.insert(), reservation) return res.lastrowid
def boot_b2g_second_stage(self): # get the boot_config and verify it fqdn = config.get('server', 'fqdn') url = 'http://%s/api/device/%s/bootconfig/' % (fqdn, self.name) r = requests.get(url) bootconfig = r.json() if 'b2gbase' not in bootconfig: self.logger('got invalid bootconfig - no b2gbase') raise Failure self.logger.debug('got b2gbase %r' % bootconfig['b2gbase']) self._send_event('b2g_downloading') self._wait(60, splay=30) self._send_event('b2g_extracting') self.sdcard_image = 'corrupt' self._wait(90, splay=60) self._send_event('b2g_rebooting') self._wait(3, splay=2) # time for the reboot command to do its thing self.pingable = False self.sdcard_image = 'b2g' self.boot_sdcard()
def main(run=True): # templeton uses $PWD/../html to serve /, so put PWD in a subdirectory of # the directory containing our html data. Easiest is to just change the the # html directory itself os.chdir(os.path.join(os.path.dirname(mozpool.__file__), 'html')) # Set up logging logging.basicConfig( stream=sys.stderr, level=logging.DEBUG, format="%(name)s %(levelname)s - [%(asctime)s] %(message)s") # ignore urllib3 informational logging urllib3_logger = logging.getLogger('requests.packages.urllib3') urllib3_logger.setLevel(logging.CRITICAL) logger = logging.getLogger('') logger.info('Mozpool-%s server starting' % mozpool.version) # set up the DB layer's facade db = db_setup() # if we're running fake boards, start those up if config.get('testing', 'run_fakes'): from mozpool.test import fakedevices rack = fakedevices.Rack(db) rack.start() # start up the lifeguard driver # TODO: make this configurable, as well as poll freq mozpool.lifeguard.driver = devicemachine.LifeguardDriver(db) mozpool.lifeguard.driver.start() # start up the mozpool driver mozpool.mozpool.driver = requestmachine.MozpoolDriver(db) mozpool.mozpool.driver.start() app = get_app(db) if run: app.run()
def get_engine(): """ Get a database engine object. """ with _get_engine_lock: global engine if engine is None: engine_url = config.get('database', 'engine') # optimistically recycle connections after 10m engine = sqlalchemy.create_engine(engine_url, pool_recycle=600) # and pessimistically check connections before using them sqlalchemy.event.listen(engine.pool, 'checkout', _checkout_listener) # set sqlite to WAL mode to avoid weird concurrency issues if engine.dialect.name == 'sqlite': try: engine.execute("pragma journal_mode = wal") except: pass # oh well.. return engine
def set_pxe(device_name, pxe_config_name, boot_config): """ Set up the PXE configuration for the device as directed. Note that this does *not* reboot the device. """ logger.info('setting pxe config for %s to %s%s' % (device_name, pxe_config_name, ' with boot config' if boot_config else '')) image_details = data.pxe_config_details(pxe_config_name)['details'] pxe_config_contents = image_details['contents'] # Set the config in the database before writing to disk. data.set_device_config(device_name, pxe_config_name, boot_config) # Write out the config file device_config_path = _get_device_config_path(device_name) device_config_dir = os.path.dirname(device_config_path) if not os.path.exists(device_config_dir): os.makedirs(device_config_dir) # apply ipaddress substitution to the config contents pxe_config_contents = pxe_config_contents.replace('%IPADDRESS%', config.get('server', 'ipaddress')) open(device_config_path, "w").write(pxe_config_contents)
def __init__(self, db, poll_frequency=statedriver.POLL_FREQUENCY): statedriver.StateDriver.__init__(self, db, poll_frequency) self.imaging_server_id = self.db.imaging_servers.get_id( config.get('server', 'fqdn'))
def imaging_server_id(self): if self._imaging_server_id is None: self._imaging_server_id = self.db.imaging_servers.get_id(config.get('server', 'fqdn')) return self._imaging_server_id
def sync(db, verbose=False, ship_it=False): ignore_devices_on_servers_re = None if config.has_option('inventory', 'ignore_devices_on_servers_re'): ignore_devices_on_servers_re = config.get( 'inventory', 'ignore_devices_on_servers_re') from_inv = get_devices(config.get('inventory', 'url'), config.get('inventory', 'filter'), config.get('inventory', 'username'), config.get('inventory', 'password'), ignore_devices_on_servers_re, verbose=verbose) # dump the db second, since otherwise the mysql server can go away while # get_devices is still running, which is no fun from_db = db.inventorysync.dump_devices() ## get a list of relay_boards derived from the inventory dump relay_boards_from_inv = get_relay_boards(from_inv) ## get existing relay_board list from DB relay_boards_from_db = db.inventorysync.dump_relays() # get the list of changes that need to be made tasks = list(merge_devices(from_db, from_inv)) # If there are too many changes, bail out and await human interaction. # "Too many" means more than 5 and more than a tenth of the larger of the # set of devices currently in inventory and the set in the DB. This is a # failsafe to keep the inventory sync from unexpectedly erasing all # devices. if len(tasks) > max(5, len(from_db) / 10, len(from_inv) / 10) and not ship_it: raise RuntimeError("%d changes: pass --ship-it to make these changes" % len(tasks)) # start merging devices for task in tasks: if task[0] == 'insert': if verbose: print "insert device", task[1]['fqdn'] db.inventorysync.insert_device(task[1]) elif task[0] == 'delete': if verbose: print "delete device", task[2] db.inventorysync.delete_device(task[1]) elif task[0] == 'update': if verbose: print "update device", task[2] db.inventorysync.update_device(task[1], task[2]) else: raise RuntimeError('%s is not a task' % task[0]) # start merging relay_boards for task in merge_relay_boards(relay_boards_from_db, relay_boards_from_inv): if task[0] == 'insert': if verbose: print "insert relay_board", task[1]['fqdn'] db.inventorysync.insert_relay_board(task[1]) elif task[0] == 'delete': if verbose: print "delete relay_board", task[2] db.inventorysync.delete_relay_board(task[1]) elif task[0] == 'update': if verbose: print "update relay_board", task[2] db.inventorysync.update_relay_board(task[1], task[2]) else: raise RuntimeError('%s is not a task' % task[0])
def imaging_server_id(self): if self._imaging_server_id is None: self._imaging_server_id = self.db.imaging_servers.get_id(config.get("server", "fqdn")) return self._imaging_server_id
def setup(db_url=None): if not db_url: db_url = config.get('database', 'engine') return DB(db_url)
def __init__(self, poll_frequency=statedriver.POLL_FREQUENCY): statedriver.StateDriver.__init__(self, poll_frequency) self.imaging_server_id = data.find_imaging_server_id( config.get('server', 'fqdn'))
def imaging_server_id(self): if self._imaging_server_id is None: self._imaging_server_id = self.db.imaging_servers.get_id( config.get('server', 'fqdn')) return self._imaging_server_id
def test_get_set(self): config.reset() config.set('abc', 'def', 'ghi') self.assertEqual(config.get('abc', 'def'), 'ghi') self.assertEqual(config.get('abc', 'XXX'), None) self.assertEqual(config.get('XXX', 'XXX'), None)