def provision_system(fqdn): system = _get_system_by_FQDN(fqdn) if not system.can_configure_netboot(identity.current.user): raise Forbidden403('Cannot provision system') data = read_json_request(request) with convert_internal_errors(): if not data['distro_tree'] or 'id' not in data['distro_tree']: raise ValueError('No distro tree specified') distro_tree = DistroTree.by_id(data['distro_tree']['id']) user = identity.current.user if user.rootpw_expired: raise ValueError('Your root password has expired, you must ' 'change or clear it in order to provision.') redirect(u"/view/%s" % system.fqdn) install_options = system.manual_provision_install_options(distro_tree)\ .combined_with(InstallOptions.from_strings(data.get('ks_meta'), data.get('koptions'), data.get('koptions_post'))) if 'ks' not in install_options.kernel_options: kickstart = generate_kickstart(install_options, distro_tree=distro_tree, system=system, user=user) install_options.kernel_options['ks'] = kickstart.link system.configure_netboot(distro_tree, install_options.kernel_options_str, service=u'HTTP') system.record_activity(user=identity.current.user, service=u'HTTP', action=u'Provision', field=u'Distro Tree', new=unicode(distro_tree)) if data.get('reboot'): system.action_power(action=u'reboot', service=u'HTTP') # in future "installations" will be a real thing in our model, # but for now we have nothing to return return 'Provisioned', 201
def lab_controller_add(self, distro_tree_id, lab_controller_id, url): try: distro_tree = DistroTree.by_id(distro_tree_id) except NoResultFound: flash(_(u'Invalid distro tree id %s') % distro_tree_id) redirect('.') try: lab_controller = LabController.by_id(lab_controller_id) except NoResultFound: flash(_(u'Invalid lab controller id %s') % lab_controller_id) redirect(str(distro_tree.id)) url = url.strip() if not url.endswith('/'): url = url + '/' if not urlparse.urlparse(url).scheme: flash(_(u'URL %r is not absolute') % url) redirect(str(distro_tree.id)) distro_tree.lab_controller_assocs.append( LabControllerDistroTree(lab_controller=lab_controller, url=url)) distro_tree.activity.append(DistroTreeActivity( user=identity.current.user, service=u'WEBUI', action=u'Added', field_name=u'lab_controller_assocs', old_value=None, new_value=u'%s %s' % (lab_controller, url))) flash(_(u'Added %s %s') % (lab_controller, url)) redirect(str(distro_tree.id))
def lab_controller_add(self, distro_tree_id, lab_controller_id, url): try: distro_tree = DistroTree.by_id(distro_tree_id) except NoResultFound: flash(_(u'Invalid distro tree id %s') % distro_tree_id) redirect('.') try: lab_controller = LabController.by_id(lab_controller_id) except ValueError: flash(_(u'Invalid lab controller id %s') % lab_controller_id) redirect(str(distro_tree.id)) url = url.strip() if not url.endswith('/'): url = url + '/' if not urlparse.urlparse(url).scheme: flash(_(u'URL %r is not absolute') % url) redirect(str(distro_tree.id)) distro_tree.lab_controller_assocs.append( LabControllerDistroTree(lab_controller=lab_controller, url=url)) distro_tree.activity.append(DistroTreeActivity( user=identity.current.user, service=u'WEBUI', action=u'Added', field_name=u'lab_controller_assocs', old_value=None, new_value=u'%s %s' % (lab_controller, url))) flash(_(u'Added %s %s') % (lab_controller, url)) redirect(str(distro_tree.id))
def install_options(self, distro_tree_id, **kwargs): try: distro_tree = DistroTree.by_id(distro_tree_id) except NoResultFound: flash(_(u'Invalid distro tree id %s') % distro_tree_id) redirect('.') if 'ks_meta' in kwargs: distro_tree.activity.append(DistroTreeActivity( user=identity.current.user, service=u'WEBUI', action=u'Changed', field_name=u'InstallOption:ks_meta', old_value=distro_tree.ks_meta, new_value=kwargs['ks_meta'])) distro_tree.ks_meta = kwargs['ks_meta'] if 'kernel_options' in kwargs: distro_tree.activity.append(DistroTreeActivity( user=identity.current.user, service=u'WEBUI', action=u'Changed', field_name=u'InstallOption:kernel_options', old_value=distro_tree.kernel_options, new_value=kwargs['kernel_options'])) distro_tree.kernel_options = kwargs['kernel_options'] if 'kernel_options_post' in kwargs: distro_tree.activity.append(DistroTreeActivity( user=identity.current.user, service=u'WEBUI', action=u'Changed', field_name=u'InstallOption:kernel_options_post', old_value=distro_tree.kernel_options_post, new_value=kwargs['kernel_options_post'])) distro_tree.kernel_options_post = kwargs['kernel_options_post'] flash(_(u'Updated install options')) redirect(str(distro_tree.id))
def doit(): distro_trees = [] for id in request.form.getlist('distro_tree_id'): try: distro_trees.append(DistroTree.by_id(id)) except NoResultFound: raise BadRequest400('Distro tree %r does not exist' % id) job_details = {} job_details['pick'] = request.form.get('pick') or 'auto' if job_details['pick'] == 'fqdn': try: job_details['system'] = System.by_fqdn(request.form.get('system'), identity.current.user) except NoResultFound: raise BadRequest400('System %s not found' % request.form.get('system')) elif job_details['pick'] == 'lab': try: job_details['lab'] = LabController.by_name(request.form.get('lab')) except NoResultFound: raise BadRequest400('Lab controller %s not found' % request.form.get('lab')) days = int(request.form.get('reserve_days') or DEFAULT_RESERVE_DAYS) days = min(days, MAX_DAYS_PROVISION) job_details['reservetime'] = days * 24 * 60 * 60 job_details['whiteboard'] = request.form.get('whiteboard') job_details['ks_meta'] = request.form.get('ks_meta') job_details['koptions'] = request.form.get('koptions') job_details['koptions_post'] = request.form.get('koptions_post') with convert_internal_errors(): job = Job.provision_system_job(distro_trees, **job_details) return 'Created %s' % job.t_id, 201, [('Location', url('/jobs/%s' % job.id))]
def doit(): distro_trees = [] for id in request.form.getlist('distro_tree_id'): try: distro_trees.append(DistroTree.by_id(id)) except NoResultFound: raise BadRequest400('Distro tree %r does not exist' % id) job_details = {} job_details['pick'] = request.form.get('pick') or 'auto' if job_details['pick'] == 'fqdn': try: job_details['system'] = System.by_fqdn(request.form.get('system'), identity.current.user) except NoResultFound: raise BadRequest400('System %s not found' % request.form.get('system')) elif job_details['pick'] == 'lab': try: job_details['lab'] = LabController.by_name(request.form.get('lab')) except NoResultFound: raise BadRequest400('Lab controller %s not found' % request.form.get('lab')) days = int(request.form.get('reserve_days') or DEFAULT_RESERVE_DAYS) days = min(days, MAX_DAYS_PROVISION) job_details['reservetime'] = days * 24 * 60 * 60 job_details['whiteboard'] = request.form.get('whiteboard') job_details['ks_meta'] = request.form.get('ks_meta') job_details['koptions'] = request.form.get('koptions') job_details['koptions_post'] = request.form.get('koptions_post') with convert_internal_errors(): job = Job.provision_system_job(distro_trees, **job_details) return 'Created %s' % job.t_id, 201, [('Location', absolute_url('/jobs/%s' % job.id))]
def default(self, id, *args, **kwargs): try: distro_tree = DistroTree.by_id(int(id)) except (ValueError, NoResultFound): raise cherrypy.NotFound(id) form_task = TaskSearchForm(action='/tasks/do_search', hidden=dict(arch_id=True, distro=True, osmajor_id=True), options=dict()) lab_controllers = LabController.query.filter_by(removed=None)\ .order_by(LabController.fqdn).all() lab_controller_assocs = dict((lab_controller, sorted((lca for lca in distro_tree.lab_controller_assocs if lca.lab_controller == lab_controller), key=lambda lca: lca.url)) for lab_controller in lab_controllers) is_admin = identity.current.user and identity.current.user.is_admin() or False return dict(title='Distro Tree', value=distro_tree, tabber=widgets.Tabber(use_cookie=True), install_options_widget=DistroTreeInstallOptionsWidget(), form_task=form_task, delete_link=self.delete_link, lab_controllers=lab_controllers, lab_controller_assocs=lab_controller_assocs, readonly=not is_admin)
def index(self, **kwargs): # CherryPy will give us distro_tree_id as a scalar if it only has one # value, but we want it to always be a list of int if not kwargs.get('distro_tree_id'): kwargs['distro_tree_id'] = [] elif not isinstance(kwargs['distro_tree_id'], list): kwargs['distro_tree_id'] = [int(kwargs['distro_tree_id'])] else: kwargs['distro_tree_id'] = [int(x) for x in kwargs['distro_tree_id']] # If we got a distro_tree_id but no osmajor or distro, fill those in # with the right values so that the distro picker is populated properly if kwargs['distro_tree_id']: distro_tree = DistroTree.by_id(kwargs['distro_tree_id'][0]) if not kwargs.get('distro'): kwargs['distro'] = distro_tree.distro.name if not kwargs.get('osmajor'): kwargs['osmajor'] = distro_tree.distro.osversion.osmajor.osmajor options = {} options['tag'] = [tag.tag for tag in DistroTag.used()] options['osmajor'] = [osmajor.osmajor for osmajor in OSMajor.ordered_by_osmajor(OSMajor.in_any_lab())] options['distro'] = self._get_distro_options( osmajor=kwargs.get('osmajor'), tag=kwargs.get('tag')) options['distro_tree_id'] = self._get_distro_tree_options( distro=kwargs.get('distro')) options['lab'] = [lc.fqdn for lc in LabController.query.filter(LabController.removed == None)] return dict(title=_(u'Reserve Workflow'), selection=kwargs, options=options)
def default(self, id, *args, **kwargs): try: distro_tree = DistroTree.by_id(int(id)) except (ValueError, NoResultFound): raise cherrypy.NotFound(id) form_task = TaskSearchForm(action='/tasks/do_search', hidden=dict(arch_id=True, distro=True, osmajor_id=True), options=dict()) lab_controllers = LabController.query.filter_by(removed=None)\ .order_by(LabController.fqdn).all() lab_controller_assocs = dict( (lab_controller, sorted((lca for lca in distro_tree.lab_controller_assocs if lca.lab_controller == lab_controller), key=lambda lca: lca.url)) for lab_controller in lab_controllers) is_admin = identity.current.user and identity.current.user.is_admin( ) or False return dict(title='Distro Tree', value=distro_tree, install_options_widget=DistroTreeInstallOptionsWidget(), form_task=form_task, delete_link=self.delete_link, lab_controllers=lab_controllers, lab_controller_assocs=lab_controller_assocs, readonly=not is_admin)
def yum_config(self, distro_tree_id, *args, **kwargs): # Ignore positional args, so that we can make nice URLs like # /distrotrees/yum_config/12345/RHEL-6.2-Server-i386.repo try: distro_tree = DistroTree.by_id(int(distro_tree_id)) except (ValueError, NoResultFound): raise cherrypy.NotFound(distro_tree_id) if not kwargs.get('lab'): lc = distro_tree.lab_controller_assocs[0].lab_controller else: try: lc = LabController.by_name(kwargs['lab']) except NoResultFound: raise cherrypy.HTTPError(status=400, message='No such lab controller %r' % kwargs['lab']) base = distro_tree.url_in_lab(lc, scheme='http') if not base: raise cherrypy.HTTPError(status=404, message='%s is not present in lab %s' % (distro_tree, lc)) if not distro_tree.repos: return '# No repos for %s' % distro_tree sections = [] for repo in distro_tree.repos: sections.append('''[%s] name=%s baseurl=%s enabled=1 gpgcheck=0 ''' % (repo.repo_id, repo.repo_id, urlparse.urljoin(base, repo.path))) return '\n'.join(sections)
def doit(): distro_trees = [] for id in request.form.getlist('distro_tree_id'): try: distro_trees.append(DistroTree.by_id(id)) except NoResultFound: raise BadRequest400('Distro tree %r does not exist' % id) job_details = {} job_details['pick'] = request.form.get('pick') or 'auto' system_choice = 'any system' if job_details['pick'] == 'fqdn': try: job_details['system'] = System.by_fqdn(request.form.get('system'), identity.current.user) system_choice = 'a specific system' except DatabaseLookupError: raise BadRequest400('System %s not found' % request.form.get('system')) elif job_details['pick'] == 'lab': try: job_details['lab'] = LabController.by_name(request.form.get('lab')) system_choice = 'any lab system' except NoResultFound: raise BadRequest400('Lab controller %s not found' % request.form.get('lab')) reservetime = int( request.form.get('reserve_duration') or DEFAULT_RESERVE_SECONDS) if reservetime > MAX_SECONDS_PROVISION: raise BadRequest400( 'Reservation time exceeds maximum time of %s hours' % MAX_HOURS_PROVISION) job_details['reservetime'] = reservetime job_details['whiteboard'] = request.form.get('whiteboard') if not job_details['whiteboard']: job_details['whiteboard'] = ( "Reserve Workflow provision of distro %s on %s for %d seconds" % (request.form.get('distro'), system_choice, job_details['reservetime'])) job_details['ks_meta'] = request.form.get('ks_meta') job_details['koptions'] = request.form.get('koptions') job_details['koptions_post'] = request.form.get('koptions_post') with convert_internal_errors(): job = Job.provision_system_job(distro_trees, **job_details) return 'Created %s' % job.t_id, 201, [('Location', absolute_url('/jobs/%s' % job.id))]
def reserve(self, distro_tree_id, system_id=None, lab_controller_id=None): """ Either queue or provision the system now """ if system_id == 'search': redirect('/reserve_system', distro_tree_id=distro_tree_id) elif system_id: try: system = System.by_id(system_id, identity.current.user) except InvalidRequestError: flash(_(u'Invalid System ID %s' % system_id)) system_name = system.fqdn else: system_name = 'Any System' distro_names = [] return_value = dict( system_id = system_id, system = system_name, distro = '', distro_tree_ids = [], ) warn = None if not isinstance(distro_tree_id, list): distro_tree_id = [distro_tree_id] for id in distro_tree_id: try: distro_tree = DistroTree.by_id(id) if System.by_type(type=SystemType.machine, systems=distro_tree.systems(user=identity.current.user))\ .count() < 1: warn = _(u'No systems compatible with %s') % distro_tree distro_names.append(unicode(distro_tree)) return_value['distro_tree_ids'].append(id) except NoResultFound: flash(_(u'Invalid distro tree ID %s') % id) distro = ", ".join(distro_names) return_value['distro'] = distro return dict(form=self.reserveform, action='./doit', value = return_value, warn=warn, options = None, title='Reserve %s' % system_name)
def index(self, **kwargs): # CherryPy will give us distro_tree_id as a scalar if it only has one # value, but we want it to always be a list of int if not kwargs.get('distro_tree_id'): kwargs['distro_tree_id'] = [] elif not isinstance(kwargs['distro_tree_id'], list): kwargs['distro_tree_id'] = [int(kwargs['distro_tree_id'])] else: kwargs['distro_tree_id'] = [ int(x) for x in kwargs['distro_tree_id'] ] # If we got a distro_tree_id but no osmajor or distro, fill those in # with the right values so that the distro picker is populated properly if kwargs['distro_tree_id']: distro_tree = DistroTree.by_id(kwargs['distro_tree_id'][0]) if not kwargs.get('distro'): kwargs['distro'] = distro_tree.distro.name if not kwargs.get('osmajor'): kwargs[ 'osmajor'] = distro_tree.distro.osversion.osmajor.osmajor options = {} options['tag'] = [tag.tag for tag in DistroTag.used()] options['osmajor'] = [ osmajor.osmajor for osmajor in OSMajor.ordered_by_osmajor(OSMajor.in_any_lab()) ] options['distro'] = self._get_distro_options( osmajor=kwargs.get('osmajor'), tag=kwargs.get('tag')) options['distro_tree_id'] = self._get_distro_tree_options( distro=kwargs.get('distro')) options['lab'] = [ lc.fqdn for lc in LabController.query.filter(LabController.removed == None) ] return dict(title=_(u'Reserve Workflow'), selection=kwargs, options=options)
def lab_controller_add(self, distro_tree_id, lab_controller_id, url): try: distro_tree = DistroTree.by_id(distro_tree_id) except NoResultFound: flash(_(u'Invalid distro tree id %s') % distro_tree_id) redirect('.') try: lab_controller = LabController.by_id(lab_controller_id) except ValueError: flash(_(u'Invalid lab controller id %s') % lab_controller_id) redirect(str(distro_tree.id)) # make sure the url ends with / url = os.path.join(url.strip(), '') try: self.add_distro_urls(distro_tree, lab_controller, [url]) except ValueError as e: flash(_(u'%s') % e) redirect(str(distro_tree.id)) flash(_(u'Changed/Added %s %s') % (lab_controller, url)) redirect(str(distro_tree.id))
def update_system(fqdn): system = _get_system_by_FQDN(fqdn) if not system.can_edit(identity.current.user): raise Forbidden403('Cannot edit system') data = read_json_request(request) # helper for recording activity below def record_activity(field, old, new, action=u'Changed'): system.record_activity(user=identity.current.user, service=u'HTTP', action=action, field=field, old=old, new=new) with convert_internal_errors(): # XXX what a nightmare... need to use a validation/conversion library, # and maybe simplify/relocate the activity recording stuff somehow changed = False renamed = False if 'fqdn' in data: new_fqdn = data['fqdn'].lower() if new_fqdn != system.fqdn: if System.query.filter(System.fqdn == new_fqdn).count(): raise Conflict409('System %s already exists' % new_fqdn) record_activity(u'FQDN', system.fqdn, new_fqdn) system.fqdn = new_fqdn changed = True renamed = True if 'owner' in data and data['owner'].get('user_name') != system.owner.user_name: if not system.can_change_owner(identity.current.user): raise Forbidden403('Cannot change owner') new_owner = User.by_user_name(data['owner'].get('user_name')) if new_owner is None: raise BadRequest400('No such user %s' % data['owner'].get('user_name')) record_activity(u'Owner', system.owner, new_owner) system.owner = new_owner changed = True if 'status' in data: new_status = SystemStatus.from_string(data['status']) if new_status != system.status: record_activity(u'Status', system.status, new_status) system.status = new_status if not new_status.bad and system.status_reason: # clear the status reason for "good" statuses record_activity(u'Status Reason', system.status_reason, None) system.status_reason = None changed = True if 'status_reason' in data: new_reason = data['status_reason'] or None if new_reason and not system.status.bad: raise ValueError('Cannot set status reason when status is %s' % system.status) if new_reason != system.status_reason: record_activity(u'Status Reason', system.status_reason, new_reason) system.status_reason = new_reason changed = True if 'type' in data: new_type = SystemType.from_string(data['type']) if new_type != system.type: record_activity(u'Type', system.type, new_type) system.type = new_type changed = True if 'arches' in data: new_arches = [Arch.by_name(a) for a in (data['arches'] or [])] added_arches = set(new_arches).difference(system.arch) removed_arches = set(system.arch).difference(new_arches) if added_arches or removed_arches: for added_arch in added_arches: record_activity(u'Arch', None, added_arch, u'Added') for removed_arch in removed_arches: record_activity(u'Arch', removed_arch, None, u'Removed') system.arch[:] = new_arches changed = True if 'lab_controller_id' in data: if data['lab_controller_id']: new_lc = LabController.by_id(data['lab_controller_id']) else: new_lc = None if new_lc != system.lab_controller: if system.open_reservation is not None: raise Conflict409('Unable to change lab controller while system ' 'is in use (return the system first)') record_activity(u'Lab Controller', system.lab_controller, new_lc) system.lab_controller = new_lc changed = True # If we're given any power-related keys, need to ensure system.power exists if not system.power and set(['power_type', 'power_address', 'power_user', 'power_password', 'power_id', 'power_quiescent_period'])\ .intersection(data.keys()): system.power = Power() if 'power_type' in data: new_power_type = PowerType.by_name(data['power_type']) if new_power_type != system.power.power_type: if not system.power.power_type: old_power_type = '' else: old_power_type = system.power.power_type.name record_activity(u'power_type', old_power_type, new_power_type.name) system.power.power_type = new_power_type changed = True if 'power_address' in data: new_power_address = data['power_address'] if not new_power_address: raise ValueError('Power address is required') if new_power_address != system.power.power_address: record_activity(u'power_address', system.power.power_address, data['power_address']) system.power.power_address = new_power_address changed = True if 'power_user' in data: new_power_user = data['power_user'] or u'' if new_power_user != (system.power.power_user or u''): record_activity(u'power_user', u'********', u'********') system.power.power_user = new_power_user changed = True if 'power_password' in data: new_power_password = data['power_password'] or u'' if new_power_password != (system.power.power_passwd or u''): record_activity(u'power_passwd', u'********', u'********') system.power.power_passwd = new_power_password changed = True if 'power_id' in data: new_power_id = data['power_id'] or u'' if new_power_id != (system.power.power_id or u''): record_activity(u'power_id', system.power.power_id, new_power_id) system.power.power_id = new_power_id changed = True if 'power_quiescent_period' in data: new_qp = int(data['power_quiescent_period']) if new_qp != system.power.power_quiescent_period: record_activity(u'power_quiescent_period', system.power.power_quiescent_period, new_qp) system.power.power_quiescent_period = new_qp changed = True if 'release_action' in data: new_release_action = ReleaseAction.from_string(data['release_action']) if new_release_action != (system.release_action or ReleaseAction.power_off): record_activity(u'release_action', (system.release_action or ReleaseAction.power_off), new_release_action) system.release_action = new_release_action changed = True if 'reprovision_distro_tree' in data: if (not data['reprovision_distro_tree'] or 'id' not in data['reprovision_distro_tree']): new_rpdt = None else: new_rpdt = DistroTree.by_id(data['reprovision_distro_tree']['id']) if new_rpdt != system.reprovision_distro_tree: record_activity(u'reprovision_distro_tree', unicode(system.reprovision_distro_tree), unicode(new_rpdt)) system.reprovision_distro_tree = new_rpdt changed = True if 'location' in data: new_location = data['location'] or None if new_location != system.location: record_activity(u'Location', system.location, new_location) system.location = new_location changed = True if 'lender' in data: new_lender = data['lender'] or None if new_lender != system.lender: record_activity(u'Lender', system.lender, new_lender) system.lender = new_lender changed = True if 'kernel_type' in data: new_kernel_type = KernelType.by_name(data['kernel_type']) if new_kernel_type != system.kernel_type: record_activity(u'Kernel Type', system.kernel_type, new_kernel_type) system.kernel_type = new_kernel_type changed = True if 'hypervisor' in data: if data['hypervisor']: new_hypervisor = Hypervisor.by_name(data['hypervisor']) else: new_hypervisor = None if new_hypervisor != system.hypervisor: record_activity(u'Hypervisor', system.hypervisor, new_hypervisor) system.hypervisor = new_hypervisor changed = True if 'vendor' in data: new_vendor = data['vendor'] or None if new_vendor != system.vendor: record_activity(u'Vendor', system.vendor, new_vendor) system.vendor = new_vendor changed = True if 'model' in data: new_model = data['model'] or None if new_model != system.model: record_activity(u'Model', system.model, new_model) system.model = new_model changed = True if 'serial_number' in data: new_serial_number = data['serial_number'] or None if new_serial_number != system.serial: record_activity(u'Serial Number', system.serial, new_serial_number) system.serial = new_serial_number changed = True if 'mac_address' in data: new_mac_address = data['mac_address'] or None if new_mac_address != system.mac_address: record_activity(u'MAC Address', system.mac_address, new_mac_address) system.mac_address = new_mac_address changed = True if 'memory' in data: new_memory = int(data['memory']) if data['memory'] else None if new_memory != system.memory: record_activity(u'Memory', system.memory, new_memory) system.memory = new_memory changed = True if 'numa_nodes' in data: new_numa_nodes = int(data['numa_nodes']) if data['numa_nodes'] else None if not system.numa: system.numa = Numa() if new_numa_nodes != system.numa.nodes: record_activity(u'NUMA/Nodes', system.numa.nodes, new_numa_nodes) system.numa.nodes = new_numa_nodes changed = True if changed: # XXX clear checksum!? system.date_modified = datetime.datetime.utcnow() response = jsonify(system.__json__()) if renamed: response.headers.add('Location', url('/view/%s' % system.fqdn)) return response
def provision(self, fqdn, distro_tree_id, ks_meta=None, kernel_options=None, kernel_options_post=None, kickstart=None, reboot=True): """ Provisions a system with the given distro tree and options. The *ks_meta*, *kernel_options*, and *kernel_options_post* arguments override the default values configured for the system. For example, if the default kernel options for the system/distro are 'console=ttyS0 ksdevice=eth0', and the caller passes 'ksdevice=eth1' for *kernel_options*, the kernel options used will be 'console=ttyS0 ksdevice=eth1'. :param distro_tree_id: numeric id of distro tree to be provisioned :type distro_tree_id: int :param ks_meta: kickstart options :type ks_meta: str :param kernel_options: kernel options for installation :type kernel_options: str :param kernel_options_post: kernel options for after installation :type kernel_options_post: str :param kickstart: complete kickstart :type kickstart: str :param reboot: whether to reboot the system after applying Cobbler changes :type reboot: bool .. versionadded:: 0.6 .. versionchanged:: 0.6.10 System-specific kickstart/kernel options are now obeyed. .. versionchanged:: 0.9 *distro_install_name* parameter is replaced with *distro_tree_id*. See :meth:`distrotrees.filter`. """ system = System.by_fqdn(fqdn, identity.current.user) if not system.can_provision_now(identity.current.user): raise BX(_(u'User %s has insufficient permissions to provision %s') % (identity.current.user.user_name, system.fqdn)) if not system.user == identity.current.user: raise BX(_(u'Reserve a system before provisioning')) distro_tree = DistroTree.by_id(distro_tree_id) # sanity check: does the distro tree apply to this system? if distro_tree.systems().filter(System.id == system.id).count() < 1: raise BX(_(u'Distro tree %s cannot be provisioned on %s') % (distro_tree, system.fqdn)) if identity.current.user.rootpw_expired: raise BX(_('Your root password has expired, please change or clear it in order to submit jobs.')) # ensure system-specific defaults are used # (overriden by this method's arguments) options = system.install_options(distro_tree).combined_with( InstallOptions.from_strings(ks_meta or '', kernel_options or '', kernel_options_post or '')) if 'ks' not in options.kernel_options: rendered_kickstart = generate_kickstart(options, distro_tree=distro_tree, system=system, user=identity.current.user, kickstart=kickstart) options.kernel_options['ks'] = rendered_kickstart.link system.configure_netboot(distro_tree, options.kernel_options_str, service=u'XMLRPC') system.activity.append(SystemActivity(user=identity.current.user, service=u'XMLRPC', action=u'Provision', field_name=u'Distro Tree', old_value=u'', new_value=u'Success: %s' % distro_tree)) if reboot: system.action_power(action='reboot', service=u'XMLRPC') return system.fqdn # because turbogears makes us return something
def main(*args): parser = optparse.OptionParser('usage: %prog [options]', description=__description__, version=__version__) parser.add_option('-u', '--user', metavar='USERNAME', help='The user we are creating a kickstart for', default='admin') parser.add_option('-r', '--recipe-id', metavar='ID', help='Recreate kickstart based on recipe ID') parser.add_option('-d', '--distro-tree-id', metavar='ID', help='Recreate kickstart based on distro ID') parser.add_option('-t', '--template-dir', metavar='DIR', help='Retrieve templates from DIR') parser.add_option('-f', '--system', metavar='FQDN', help='Generate kickstart for system identified by FQDN') parser.add_option('-m', '--ks-meta', metavar='OPTIONS', default='', help='Kickstart meta data') parser.add_option('-p', '--kernel-options-post', metavar='OPTIONS', default='', help='Kernel options post') options, args = parser.parse_args(*args) ks_meta = options.ks_meta.decode(sys.getfilesystemencoding()) koptions_post = options.kernel_options_post.decode(sys.getfilesystemencoding()) template_dir = options.template_dir if template_dir: add_to_template_searchpath(template_dir) if not options.recipe_id: if not options.distro_tree_id and not options.system: parser.error('Must specify either a recipe or a distro tree and system') elif not options.distro_tree_id: parser.error('Must specify a distro tree id when passing in a system') elif not options.system: parser.error('Must specify a system when not specifying a recipe') load_config_or_exit() with session.begin(): user = User.by_user_name(options.user.decode(sys.getfilesystemencoding())) ks_appends = None recipe = None distro_tree = None system = None install_options = None if options.distro_tree_id: try: distro_tree = DistroTree.by_id(options.distro_tree_id) except NoResultFound: raise RuntimeError("Distro tree id '%s' does not exist" % options.distro_tree_id) if options.system: fqdn = options.system.decode(sys.getfilesystemencoding()) try: system = System.by_fqdn(fqdn, user) except DatabaseLookupError: raise RuntimeError("System '%s' does not exist" % fqdn) if distro_tree and not options.recipe_id: install_options = system.manual_provision_install_options(distro_tree)\ .combined_with(InstallOptions.from_strings(ks_meta, None, koptions_post)) if options.recipe_id: try: recipe = Recipe.by_id(options.recipe_id) except NoResultFound: raise RuntimeError("Recipe id '%s' does not exist" % options.recipe_id) if not recipe.resource and not options.system: raise RuntimeError('Recipe must have (or had) a resource' ' assigned to it') if not system: system = getattr(recipe.resource, 'system', None) if not distro_tree: distro_tree = recipe.distro_tree sources = [] # if distro_tree is specified, distro_tree overrides recipe osmajor = distro_tree.distro.osversion.osmajor.osmajor if distro_tree else recipe.installation.osmajor osminor = distro_tree.distro.osversion.osminor if distro_tree else recipe.installation.osminor variant = distro_tree.variant if distro_tree else recipe.installation.variant arch = distro_tree.arch if distro_tree else recipe.installation.arch sources.append(install_options_for_distro(osmajor, osminor, variant, arch)) if distro_tree: sources.append(distro_tree.install_options()) sources.extend(system.install_options(arch, osmajor, osminor)) sources.append(recipe.generated_install_options()) sources.append(InstallOptions.from_strings(recipe.ks_meta, recipe.kernel_options, recipe.kernel_options_post)) sources.append(InstallOptions.from_strings(ks_meta, None, koptions_post)) install_options = InstallOptions.reduce(sources) ks_appends = [ks_append.ks_append for ks_append \ in recipe.ks_appends] user = recipe.recipeset.job.owner # Render the kickstart installation = recipe.installation if recipe and recipe.installation else \ FakeInstallation(distro_tree.distro.osversion.osmajor.osmajor, distro_tree.distro.osversion.osminor, distro_tree.distro.name, distro_tree.variant, distro_tree.arch, distro_tree.url_in_lab(lab_controller=system.lab_controller)) rendered_kickstart = generate_kickstart(install_options=install_options, distro_tree=distro_tree, installation=installation, system=system, user=user, recipe=recipe, ks_appends=ks_appends) kickstart = rendered_kickstart.kickstart print kickstart
def remove_distro_trees(self, distro_tree_ids): lab_controller = identity.current.user.lab_controller for distro_tree_id in distro_tree_ids: distro_tree = DistroTree.by_id(distro_tree_id) distro_tree.expire(lab_controller=lab_controller) return True
def main(*args): parser = optparse.OptionParser('usage: %prog [options]', description=__description__, version=__version__) parser.add_option('-u', '--user', metavar='USERNAME', help='The user we are creating a kickstart for', default='admin') parser.add_option('-r', '--recipe-id', metavar='ID', help='Recreate kickstart based on recipe ID') parser.add_option('-d', '--distro-tree-id', metavar='ID', help='Recreate kickstart based on distro ID') parser.add_option('-t', '--template-dir', metavar='DIR', help='Retrieve templates from DIR') parser.add_option('-f', '--system', metavar='FQDN', help='Generate kickstart for system identified by FQDN') parser.add_option('-m', '--ks-meta', metavar='OPTIONS', help='Kickstart meta data') parser.add_option('-p', '--kernel-options-post', metavar='OPTIONS', help='Kernel options post') options, args = parser.parse_args(*args) ks_meta = options.ks_meta koptions_post = options.kernel_options_post template_dir = options.template_dir if template_dir: add_to_template_searchpath(template_dir) if not options.recipe_id: if not options.distro_tree_id and not options.system: parser.error('Must specify either a recipe or a distro tree and system') elif not options.distro_tree_id: parser.error('Must specify a distro tree id when passing in a system') elif not options.system: parser.error('Must specify a system when not specifying a recipe') load_config_or_exit() with session.begin(): user = User.by_user_name(options.user) ks_appends = None recipe = None distro_tree = None system = None install_options = None if options.distro_tree_id: try: distro_tree = DistroTree.by_id(options.distro_tree_id) except NoResultFound: raise RuntimeError("Distro tree id '%s' does not exist" % options.distro_tree_id) if options.system: fqdn = options.system try: system = System.by_fqdn(fqdn, user) except NoResultFound: raise RuntimeError("System '%s' does not exist" % fqdn) if distro_tree and not options.recipe_id: install_options = system.manual_provision_install_options(distro_tree)\ .combined_with(InstallOptions.from_strings(ks_meta, None, koptions_post)) if options.recipe_id: try: recipe = Recipe.by_id(options.recipe_id) except NoResultFound: raise RuntimeError("Recipe id '%s' does not exist" % options.recipe_id) if not recipe.resource and not options.system: raise RuntimeError('Recipe must have (or had) a resource' ' assigned to it') if not system: system = getattr(recipe.resource, 'system', None) if not distro_tree: distro_tree = recipe.distro_tree install_options = InstallOptions.reduce(chain( [global_install_options()], distro_tree.install_options(), system.install_options(distro_tree), [recipe.generated_install_options(), InstallOptions.from_strings(recipe.ks_meta, recipe.kernel_options, recipe.kernel_options_post), InstallOptions.from_strings(ks_meta, None, koptions_post)])) ks_appends = [ks_append.ks_append for ks_append \ in recipe.ks_appends] user = recipe.recipeset.job.owner # Render the kickstart rendered_kickstart = generate_kickstart(install_options, distro_tree=distro_tree, system=system, user=user, recipe=recipe, ks_appends=ks_appends) kickstart = rendered_kickstart.kickstart print kickstart
def provision(self, fqdn, distro_tree_id, ks_meta=None, kernel_options=None, kernel_options_post=None, kickstart=None, reboot=True): """ Provisions a system with the given distro tree and options. The *ks_meta*, *kernel_options*, and *kernel_options_post* arguments override the default values configured for the system. For example, if the default kernel options for the system/distro are 'console=ttyS0 ksdevice=eth0', and the caller passes 'ksdevice=eth1' for *kernel_options*, the kernel options used will be 'console=ttyS0 ksdevice=eth1'. :param distro_tree_id: numeric id of distro tree to be provisioned :type distro_tree_id: int :param ks_meta: kickstart options :type ks_meta: str :param kernel_options: kernel options for installation :type kernel_options: str :param kernel_options_post: kernel options for after installation :type kernel_options_post: str :param kickstart: complete kickstart :type kickstart: str :param reboot: whether to reboot the system after applying Cobbler changes :type reboot: bool .. versionadded:: 0.6 .. versionchanged:: 0.6.10 System-specific kickstart/kernel options are now obeyed. .. versionchanged:: 0.9 *distro_install_name* parameter is replaced with *distro_tree_id*. See :meth:`distrotrees.filter`. """ system = System.by_fqdn(fqdn, identity.current.user) if not system.user == identity.current.user: raise BX(_(u'Reserve a system before provisioning')) distro_tree = DistroTree.by_id(distro_tree_id) # sanity check: does the distro tree apply to this system? if not system.compatible_with_distro_tree(distro_tree): raise BX( _(u'Distro tree %s cannot be provisioned on %s') % (distro_tree, system.fqdn)) if not system.lab_controller: raise BX(_(u'System is not attached to a lab controller')) if not distro_tree.url_in_lab(system.lab_controller): raise BX( _(u'Distro tree %s is not available in lab %s') % (distro_tree, system.lab_controller)) if identity.current.user.rootpw_expired: raise BX( _('Your root password has expired, please change or clear it in order to submit jobs.' )) # ensure system-specific defaults are used # (overriden by this method's arguments) options = system.manual_provision_install_options(distro_tree)\ .combined_with(InstallOptions.from_strings( ks_meta or '', kernel_options or '', kernel_options_post or '')) if 'ks' not in options.kernel_options: rendered_kickstart = generate_kickstart(options, distro_tree=distro_tree, system=system, user=identity.current.user, kickstart=kickstart) options.kernel_options['ks'] = rendered_kickstart.link system.configure_netboot(distro_tree, options.kernel_options_str, service=u'XMLRPC') system.record_activity(user=identity.current.user, service=u'XMLRPC', action=u'Provision', field=u'Distro Tree', old=u'', new=u'Success: %s' % distro_tree) if reboot: system.action_power(action='reboot', service=u'XMLRPC') return system.fqdn # because turbogears makes us return something
def update_system(fqdn): system = _get_system_by_FQDN(fqdn) if not system.can_edit(identity.current.user): raise Forbidden403('Cannot edit system') data = read_json_request(request) # helper for recording activity below def record_activity(field, old, new, action=u'Changed'): system.record_activity(user=identity.current.user, service=u'HTTP', action=action, field=field, old=old, new=new) with convert_internal_errors(): # XXX what a nightmare... need to use a validation/conversion library, # and maybe simplify/relocate the activity recording stuff somehow changed = False renamed = False if 'fqdn' in data: new_fqdn = data['fqdn'].lower() if new_fqdn != system.fqdn: if System.query.filter(System.fqdn == new_fqdn).count(): raise Conflict409('System %s already exists' % new_fqdn) record_activity(u'FQDN', system.fqdn, new_fqdn) system.fqdn = new_fqdn changed = True renamed = True if 'owner' in data and data['owner'].get( 'user_name') != system.owner.user_name: if not system.can_change_owner(identity.current.user): raise Forbidden403('Cannot change owner') new_owner = User.by_user_name(data['owner'].get('user_name')) if new_owner is None: raise BadRequest400('No such user %s' % data['owner'].get('user_name')) record_activity(u'Owner', system.owner, new_owner) system.owner = new_owner changed = True if 'status' in data: new_status = SystemStatus.from_string(data['status']) if new_status != system.status: record_activity(u'Status', system.status, new_status) system.status = new_status if not new_status.bad and system.status_reason: # clear the status reason for "good" statuses record_activity(u'Status Reason', system.status_reason, None) system.status_reason = None changed = True if 'status_reason' in data: new_reason = data['status_reason'] or None if new_reason and not system.status.bad: raise ValueError('Cannot set status reason when status is %s' % system.status) if new_reason != system.status_reason: record_activity(u'Status Reason', system.status_reason, new_reason) system.status_reason = new_reason changed = True if 'type' in data: new_type = SystemType.from_string(data['type']) if new_type != system.type: record_activity(u'Type', system.type, new_type) system.type = new_type changed = True if 'arches' in data: new_arches = [Arch.by_name(a) for a in (data['arches'] or [])] added_arches = set(new_arches).difference(system.arch) removed_arches = set(system.arch).difference(new_arches) if added_arches or removed_arches: for added_arch in added_arches: record_activity(u'Arch', None, added_arch, u'Added') for removed_arch in removed_arches: record_activity(u'Arch', removed_arch, None, u'Removed') system.arch[:] = new_arches changed = True if 'lab_controller_id' in data: if data['lab_controller_id']: new_lc = LabController.by_id(data['lab_controller_id']) else: new_lc = None if new_lc != system.lab_controller: if system.open_reservation is not None: raise Conflict409( 'Unable to change lab controller while system ' 'is in use (return the system first)') record_activity(u'Lab Controller', system.lab_controller, new_lc) system.lab_controller = new_lc changed = True # If we're given any power-related keys, need to ensure system.power exists if not system.power and set(['power_type', 'power_address', 'power_user', 'power_password', 'power_id', 'power_quiescent_period'])\ .intersection(data.keys()): system.power = Power() if 'power_type' in data: new_power_type = PowerType.by_name(data['power_type']) if new_power_type != system.power.power_type: if not system.power.power_type: old_power_type = '' else: old_power_type = system.power.power_type.name record_activity(u'power_type', old_power_type, new_power_type.name) system.power.power_type = new_power_type changed = True if 'power_address' in data: new_power_address = data['power_address'] if not new_power_address: raise ValueError('Power address is required') if new_power_address != system.power.power_address: record_activity(u'power_address', system.power.power_address, data['power_address']) system.power.power_address = new_power_address changed = True if 'power_user' in data: new_power_user = data['power_user'] or u'' if new_power_user != (system.power.power_user or u''): record_activity(u'power_user', u'********', u'********') system.power.power_user = new_power_user changed = True if 'power_password' in data: new_power_password = data['power_password'] or u'' if new_power_password != (system.power.power_passwd or u''): record_activity(u'power_passwd', u'********', u'********') system.power.power_passwd = new_power_password changed = True if 'power_id' in data: new_power_id = data['power_id'] or u'' if new_power_id != (system.power.power_id or u''): record_activity(u'power_id', system.power.power_id, new_power_id) system.power.power_id = new_power_id changed = True if 'power_quiescent_period' in data: new_qp = int(data['power_quiescent_period']) if new_qp != system.power.power_quiescent_period: record_activity(u'power_quiescent_period', system.power.power_quiescent_period, new_qp) system.power.power_quiescent_period = new_qp changed = True if 'release_action' in data: new_release_action = ReleaseAction.from_string( data['release_action']) if new_release_action != (system.release_action or ReleaseAction.power_off): record_activity( u'release_action', (system.release_action or ReleaseAction.power_off), new_release_action) system.release_action = new_release_action changed = True if 'reprovision_distro_tree' in data: if (not data['reprovision_distro_tree'] or 'id' not in data['reprovision_distro_tree']): new_rpdt = None else: new_rpdt = DistroTree.by_id( data['reprovision_distro_tree']['id']) if new_rpdt != system.reprovision_distro_tree: record_activity(u'reprovision_distro_tree', unicode(system.reprovision_distro_tree), unicode(new_rpdt)) system.reprovision_distro_tree = new_rpdt changed = True if 'location' in data: new_location = data['location'] or None if new_location != system.location: record_activity(u'Location', system.location, new_location) system.location = new_location changed = True if 'lender' in data: new_lender = data['lender'] or None if new_lender != system.lender: record_activity(u'Lender', system.lender, new_lender) system.lender = new_lender changed = True if 'kernel_type' in data: new_kernel_type = KernelType.by_name(data['kernel_type']) if new_kernel_type != system.kernel_type: record_activity(u'Kernel Type', system.kernel_type, new_kernel_type) system.kernel_type = new_kernel_type changed = True if 'hypervisor' in data: if data['hypervisor']: new_hypervisor = Hypervisor.by_name(data['hypervisor']) else: new_hypervisor = None if new_hypervisor != system.hypervisor: record_activity(u'Hypervisor', system.hypervisor, new_hypervisor) system.hypervisor = new_hypervisor changed = True if 'vendor' in data: new_vendor = data['vendor'] or None if new_vendor != system.vendor: record_activity(u'Vendor', system.vendor, new_vendor) system.vendor = new_vendor changed = True if 'model' in data: new_model = data['model'] or None if new_model != system.model: record_activity(u'Model', system.model, new_model) system.model = new_model changed = True if 'serial_number' in data: new_serial_number = data['serial_number'] or None if new_serial_number != system.serial: record_activity(u'Serial Number', system.serial, new_serial_number) system.serial = new_serial_number changed = True if 'mac_address' in data: new_mac_address = data['mac_address'] or None if new_mac_address != system.mac_address: record_activity(u'MAC Address', system.mac_address, new_mac_address) system.mac_address = new_mac_address changed = True if 'memory' in data: new_memory = int(data['memory']) if data['memory'] else None if new_memory != system.memory: record_activity(u'Memory', system.memory, new_memory) system.memory = new_memory changed = True if 'numa_nodes' in data: new_numa_nodes = int( data['numa_nodes']) if data['numa_nodes'] else None if not system.numa: system.numa = Numa() if new_numa_nodes != system.numa.nodes: record_activity(u'NUMA/Nodes', system.numa.nodes, new_numa_nodes) system.numa.nodes = new_numa_nodes changed = True if changed: # XXX clear checksum!? system.date_modified = datetime.datetime.utcnow() response = jsonify(system.__json__()) if renamed: response.headers.add('Location', url('/view/%s' % system.fqdn)) return response
def main(*args): parser = optparse.OptionParser('usage: %prog [options]', description=__description__, version=__version__) parser.add_option('-u', '--user', metavar='USERNAME', help='The user we are creating a kickstart for', default='admin') parser.add_option('-r', '--recipe-id', metavar='ID', help='Recreate kickstart based on recipe ID') parser.add_option('-d', '--distro-tree-id', metavar='ID', help='Recreate kickstart based on distro ID') parser.add_option('-t', '--template-dir', metavar='DIR', help='Retrieve templates from DIR') parser.add_option('-f', '--system', metavar='FQDN', help='Generate kickstart for system identified by FQDN') parser.add_option('-m', '--ks-meta', metavar='OPTIONS', help='Kickstart meta data') parser.add_option('-p', '--kernel-options-post', metavar='OPTIONS', help='Kernel options post') options, args = parser.parse_args(*args) ks_meta = options.ks_meta koptions_post = options.kernel_options_post template_dir = options.template_dir if template_dir: add_to_template_searchpath(template_dir) if not options.recipe_id: if not options.distro_tree_id and not options.system: parser.error( 'Must specify either a recipe or a distro tree and system') elif not options.distro_tree_id: parser.error( 'Must specify a distro tree id when passing in a system') elif not options.system: parser.error('Must specify a system when not specifying a recipe') load_config_or_exit() with session.begin(): user = User.by_user_name(options.user) ks_appends = None recipe = None distro_tree = None system = None install_options = None if options.distro_tree_id: try: distro_tree = DistroTree.by_id(options.distro_tree_id) except NoResultFound: raise RuntimeError("Distro tree id '%s' does not exist" % options.distro_tree_id) if options.system: fqdn = options.system try: system = System.by_fqdn(fqdn, user) except NoResultFound: raise RuntimeError("System '%s' does not exist" % fqdn) if distro_tree and not options.recipe_id: install_options = system.manual_provision_install_options(distro_tree)\ .combined_with(InstallOptions.from_strings(ks_meta, None, koptions_post)) if options.recipe_id: try: recipe = Recipe.by_id(options.recipe_id) except NoResultFound: raise RuntimeError("Recipe id '%s' does not exist" % options.recipe_id) if not recipe.resource and not options.system: raise RuntimeError('Recipe must have (or had) a resource' ' assigned to it') if not system: system = getattr(recipe.resource, 'system', None) if not distro_tree: distro_tree = recipe.distro_tree install_options = InstallOptions.reduce( chain([global_install_options()], distro_tree.install_options(), system.install_options(distro_tree), [ recipe.generated_install_options(), InstallOptions.from_strings( recipe.ks_meta, recipe.kernel_options, recipe.kernel_options_post), InstallOptions.from_strings(ks_meta, None, koptions_post) ])) ks_appends = [ks_append.ks_append for ks_append \ in recipe.ks_appends] user = recipe.recipeset.job.owner # Render the kickstart rendered_kickstart = generate_kickstart(install_options, distro_tree=distro_tree, system=system, user=user, recipe=recipe, ks_appends=ks_appends) kickstart = rendered_kickstart.kickstart print kickstart