def should_be_default_for_arch(newservice): ''' Determine if newservice should be the baseservice of default-<arch> (i.e., first service of architecture and aliasable) Input: service object for newly created service Returns: True if default-<arch> alias should be created False otherwise ''' if newservice.image.version < 3: return False services = config.get_all_service_names() make_default = True for service in services: if service == newservice.name: continue svc = AIService(service) try: props = config.get_service_props(service) config.verify_key_properties(service, props) except config.ServiceCfgError as err: # if service is missing keys, print info and skip it print >> sys.stderr, err continue if svc.arch == newservice.arch and svc.image.version >= 3: make_default = False break logging.debug("should_be_default_for_arch service %s, arch=%s, returns %s", newservice.name, newservice.arch, make_default) return make_default
def _register_a_service(self, name, interfaces=None, port=0, comments=None): '''Method: _register_a_service, private to class Description: Register a single service on the interfaces Args interfaces - the interfaces to register the service on instance - the SMF service instance handle name - the service name to be registered port - the port that the service is listening on, if port is 0 then registering a service listed in the AI SMF service instance. comments - comments for the ad hoc registered service Returns list_sdrefs - list of service references Raises AImDNSError - if SMF status property does not exist, OR if SMF txt_record property does not exist, OR if SMF port property does not exist. ''' if not self.register_initialized: self.exclude = libaimdns.getboolean_property(common.SRVINST, common.EXCLPROP) self.networks = libaimdns.getstrings_property(common.SRVINST, common.NETSPROP) self.register_initialized = True smf_port = None # if port is 0 then processing an AI service if port == 0: serv = config.get_service_props(name) if not serv: raise AIMDNSError(cw(_('error: aiMDNSError: no such ' 'installation service "%s"') % name)) # ensure the service is enabled if config.PROP_STATUS not in serv: raise AIMDNSError(cw(_('error: aiMDNSError: installation ' 'service key "status" property does ' 'not exist'))) if serv[config.PROP_STATUS] != config.STATUS_ON: print(cw(_('warning: Installation service "%s" is not enabled ' % name))) return None smf_port = config.get_service_port(name) if not smf_port: try: smf_port = libaimdns.getinteger_property(common.SRVINST, common.PORTPROP) smf_port = str(smf_port) except libaimdns.aiMDNSError, err: raise AIMDNSError(cw(_('error: aiMDNSError: port property ' 'failure (%s)') % err))
def test_get_service_props(self): '''test get_service_props''' svc = 'mysvc' props = {'dark': 'chocolate', 'green': 'tea'} config._write_service_config(svc, props) propdict = config.get_service_props(svc) self.assertEqual(propdict['version'], config.CURRENT_VERSION) self.assertEqual(propdict['dark'], 'chocolate') self.assertEqual(propdict['green'], 'tea')
def _signal_hup(self, signum, frame): '''Method: _signal_hup, class private Description: Callback invoked when SIGHUP is received Args signum - standard argument for callback, not used frame - standard argument for callback, not used Returns None Raises None ''' # get the new service keys and iterate over them services = config.get_all_service_names() for srv in services: # is this service already registered if srv not in self.instance_services or srv not in self.sdrefs: # need to register the service if self.verbose: print _('Registering %s') % srv sdrefs = self._register_a_service(interfaces=self.interfaces, name=srv) # save the service reference list in self.sdrefs if sdrefs is not None: # self.sdrefs update, force restart of event loop self._restart_loop = True if srv in self.sdrefs: self.sdrefs[srv].extend(sdrefs) else: self.sdrefs[srv] = sdrefs # check the old service keys for removed or disabled services for srv in self.instance_services: # get the service (srv) from the instance try: serv = config.get_service_props(srv) except KeyError: # not a catastrophic error for the class as additional # services can still be processed. This error will be # caught in the service log file. sys.stderr.write( _('warning: No such installation service, ' '%s\n') % srv) # remove the service references for the now non-existent # service that was just identified. This can occur when # a service is deleted. if srv in self.sdrefs: self._restart_loop = True for sdref in self.sdrefs[srv]: sdref.close() del self.sdrefs[srv] continue # was the service removed or disabled if (srv not in services) or \ (srv in self.sdrefs and serv[config.PROP_STATUS] == config.STATUS_OFF): if self.verbose: print _('Unregistering %s') % srv # remove the registered service if srv in self.sdrefs: # self.sdrefs update, force restart of event loop self._restart_loop = True for sdref in self.sdrefs[srv]: sdref.close() del self.sdrefs[srv] # save the new services list self.instance_services = services
def _register_a_service(self, name, interfaces=None, port=0, comments=None): '''Method: _register_a_service, private to class Description: Register a single service on the interfaces Args interfaces - the interfaces to register the service on instance - the SMF service instance handle name - the service name to be registered port - the port that the service is listening on, if port is 0 then registering a service listed in the AI SMF service instance. comments - comments for the ad hoc registered service Returns list_sdrefs - list of service references Raises AImDNSError - if SMF status property does not exist, OR if SMF txt_record property does not exist, OR if SMF port property does not exist. ''' if not self.register_initialized: self.exclude = libaimdns.getboolean_property( common.SRVINST, common.EXCLPROP) self.networks = libaimdns.getstrings_property( common.SRVINST, common.NETSPROP) self.register_initialized = True smf_port = None # if port is 0 then processing an AI service if port == 0: serv = config.get_service_props(name) if not serv: raise AIMDNSError( cw( _('error: aiMDNSError: no such ' 'installation service "%s"') % name)) # ensure the service is enabled if config.PROP_STATUS not in serv: raise AIMDNSError( cw( _('error: aiMDNSError: installation ' 'service key "status" property does ' 'not exist'))) if serv[config.PROP_STATUS] != config.STATUS_ON: print( cw( _('warning: Installation service "%s" is not enabled ' % name))) return None smf_port = config.get_service_port(name) if not smf_port: try: smf_port = libaimdns.getinteger_property( common.SRVINST, common.PORTPROP) smf_port = str(smf_port) except libaimdns.aiMDNSError, err: raise AIMDNSError( cw( _('error: aiMDNSError: port property ' 'failure (%s)') % err))
def parse_options(cmd_options=None): ''' Parse and validate options ''' def check_MAC_address(option, opt_str, value, parser): ''' Check MAC address as an OptionParser callback Postcondition: sets value to proper option if check passes Raises: OptionValueError if MAC address is malformed ''' try: value = str(com.MACAddress(value)) except com.MACAddress.MACAddressError as err: raise OptionValueError(str(err)) setattr(parser.values, option.dest, value) usage = '\n' + get_usage() parser = OptionParser(usage=usage) # accept multiple -b options (so append to a list) parser.add_option("-b", "--boot-args", dest="boot_args", action="append", type="string", nargs=1, help=_("boot arguments to pass to Solaris kernel")) parser.add_option("-e", "--macaddr", dest="mac_address", action="callback", nargs=1, type="string", help=_("MAC address of client to add"), callback=check_MAC_address) parser.add_option("-n", "--service", dest="service_name", action="store", type="string", help=_("Service to associate client with"), nargs=1) (options, args) = parser.parse_args(cmd_options) if args: parser.error(_("Unexpected argument(s): %s" % args)) # check that we got a service name and mac address if options.service_name is None: parser.error( _("Service name is required " "(-n|--service <service name>).")) if options.mac_address is None: parser.error(_("MAC address is required (-e|--macaddr <macaddr>).")) # Verify that the server settings are not obviously broken. # These checks cannot be complete, but check for things which # will definitely cause failure. logging.debug("Calling %s", com.CHECK_SETUP_SCRIPT) ret = Popen([com.CHECK_SETUP_SCRIPT]).wait() if ret: raise SystemExit(1) # validate service name try: com.validate_service_name(options.service_name) except ValueError as err: raise SystemExit(err) # check that the service exists service_props = config.get_service_props(options.service_name) if not service_props: raise SystemExit( _("The specified service does not exist: %s\n") % options.service_name) # get the image_path from the service try: # set image to be a InstalladmImage object image = svc.AIService(options.service_name).image except KeyError: raise SystemExit( _("\nThe specified service does not have an " "image_path property.\n")) # ensure we are not passed bootargs for a SPARC as we do not # support that if options.boot_args and image.arch == "sparc": parser.error(_("Boot arguments not supported for SPARC clients.\n")) options.arch = image.arch logging.debug("options = %s", options) return options
def delete_specified_service(service_name, auto_remove, noprompt): ''' Delete the specified Automated Install Service Input: service_name - service name auto_remove - boolean, True if dep. aliases and clients should be removed, False otherwise noprompt - boolean, True if warning about removing default-<arch> service should be suppressed ''' logging.debug("delete_specified_service %s %s %s", service_name, auto_remove, noprompt) # get service properties svcprops = config.get_service_props(service_name) service = AIService(service_name) # If the '-r' option has not been specified, look for all # dependent aliases and clients all_aliases = config.get_aliased_services(service_name, recurse=True) if not auto_remove: all_clients = config.get_clients(service_name).keys() for ale in all_aliases: all_clients.extend(config.get_clients(ale).keys()) # if any aliases or clients are dependent on this service, exit if all_aliases or all_clients: raise SystemExit(cw(_("\nError: The following aliases and/or " "clients are dependent on this service:\n\n" "%s\n\nPlease update or delete them prior " "to deleting this service or rerun this " "command using the -r|--autoremove option " "to have them automatically removed.\n") % '\n'.join(all_aliases + all_clients))) # Prompt user if they are deleting the default-sparc or default-i386 alias if not noprompt: sname = None if service_name in DEFAULT_ARCH: sname = service_name else: default_alias = set(DEFAULT_ARCH) & set(all_aliases) if default_alias: sname = ''.join(default_alias) if sname: arch = sname.split('default-')[1] _warning = """ WARNING: The service you are deleting, or a dependent alias, is the alias for the default %(arch)s service. Without the '%(name)s' service, %(arch)s clients will fail to boot unless explicitly assigned to a service using the create-client command. """ % {'arch': arch, 'name': sname} print >> sys.stderr, cw(_(_warning)) prompt = _("Are you sure you want to delete this alias? [y/N]: ") if not com.ask_yes_or_no(prompt): raise SystemExit(1) # If there are dependent aliases or clients, then remove these first aliases = config.get_aliased_services(service_name) for dependent in aliases: logging.debug("recursively calling delete_specified_service for %s", dependent) delete_specified_service(dependent, True, True) clients = config.get_clients(service_name).keys() for dependent in clients: logging.debug("calling remove_client for %s", dependent) clientctrl.remove_client(dependent) logging.debug("now deleting service %s", service_name) # remove DHCP bootfile configuration for this service, if set remove_dhcp_configuration(service) # stop the service first (avoid pulling files out from under programs) try: service.delete() except StandardError as err: # Bail out if the service could not be unmounted during the disable, # as it won't be possible to delete necessary files. print >> sys.stderr, _("\nService could not be deleted.") raise SystemExit(err) # if this was the last service, go to maintenance config.check_for_enabled_services()
def do_disable_service(cmd_options=None): ''' Disable a service Disable the specified service and optionally update the service's properties to reflect the new status. Input: List of command line options Return: None Raises: SystemExit if missing permissions, invalid service name, or if attempt to place smf service in maintenance fails. ''' logging.debug('**** START do_disable_service ****') # check for authorization and euid try: check_auth_and_euid(SERVICE_AUTH) except UnauthorizedUserError as err: raise SystemExit(err) usage = '\n' + get_disable_usage() parser = OptionParser(usage=usage) (options, args) = parser.parse_args(cmd_options) # Check for correct number of args if len(args) != 1: if len(args) == 0: parser.error(_("Missing required argument, <svcname>")) else: parser.error(_("Too many arguments: %s") % args) svcname = args[0] # validate service name try: validate_service_name(svcname) except ValueError as err: raise SystemExit(err) if not config.is_service(svcname): err_msg = _("The service does not exist: %s\n") % svcname parser.error(err_msg) prop_data = config.get_service_props(svcname) if prop_data and config.PROP_STATUS not in prop_data: err_msg = _("The property, status, is missing for %s.\n") % svcname parser.error(err_msg) if prop_data[config.PROP_STATUS] == config.STATUS_OFF: err_msg = _("The service is not running: %s\n") % svcname parser.error(err_msg) try: logging.debug("Disabling install service %s", svcname) service = AIService(svcname) service.disable(force=True) except (config.ServiceCfgError, aismf.ServicesError, MountError) as err: raise SystemExit(err) except CalledProcessError: return 1
def _signal_hup(self, signum, frame): '''Method: _signal_hup, class private Description: Callback invoked when SIGHUP is received Args signum - standard argument for callback, not used frame - standard argument for callback, not used Returns None Raises None ''' # get the new service keys and iterate over them services = config.get_all_service_names() for srv in services: # is this service already registered if srv not in self.instance_services or srv not in self.sdrefs: # need to register the service if self.verbose: print _('Registering %s') % srv sdrefs = self._register_a_service(interfaces=self.interfaces, name=srv) # save the service reference list in self.sdrefs if sdrefs is not None: # self.sdrefs update, force restart of event loop self._restart_loop = True if srv in self.sdrefs: self.sdrefs[srv].extend(sdrefs) else: self.sdrefs[srv] = sdrefs # check the old service keys for removed or disabled services for srv in self.instance_services: # get the service (srv) from the instance try: serv = config.get_service_props(srv) except KeyError: # not a catastrophic error for the class as additional # services can still be processed. This error will be # caught in the service log file. sys.stderr.write(_('warning: No such installation service, ' '%s\n') % srv) # remove the service references for the now non-existent # service that was just identified. This can occur when # a service is deleted. if srv in self.sdrefs: self._restart_loop = True for sdref in self.sdrefs[srv]: sdref.close() del self.sdrefs[srv] continue # was the service removed or disabled if (srv not in services) or \ (srv in self.sdrefs and serv[config.PROP_STATUS] == config.STATUS_OFF): if self.verbose: print _('Unregistering %s') % srv # remove the registered service if srv in self.sdrefs: # self.sdrefs update, force restart of event loop self._restart_loop = True for sdref in self.sdrefs[srv]: sdref.close() del self.sdrefs[srv] # save the new services list self.instance_services = services
def parse_options(cmd_options=None): ''' Parse and validate options ''' def check_MAC_address(option, opt_str, value, parser): ''' Check MAC address as an OptionParser callback Postcondition: sets value to proper option if check passes Raises: OptionValueError if MAC address is malformed ''' try: value = str(com.MACAddress(value)) except com.MACAddress.MACAddressError as err: raise OptionValueError(str(err)) setattr(parser.values, option.dest, value) usage = '\n' + get_usage() parser = OptionParser(usage=usage) # accept multiple -b options (so append to a list) parser.add_option("-b", "--boot-args", dest="boot_args", action="append", type="string", nargs=1, help=_("boot arguments to pass to Illumos kernel")) parser.add_option("-e", "--macaddr", dest="mac_address", action="callback", nargs=1, type="string", help=_("MAC address of client to add"), callback=check_MAC_address) parser.add_option("-n", "--service", dest="service_name", action="store", type="string", help=_("Service to associate client with"), nargs=1) (options, args) = parser.parse_args(cmd_options) if args: parser.error(_("Unexpected argument(s): %s" % args)) # check that we got a service name and mac address if options.service_name is None: parser.error(_("Service name is required " "(-n|--service <service name>).")) if options.mac_address is None: parser.error(_("MAC address is required (-e|--macaddr <macaddr>).")) # Verify that the server settings are not obviously broken. # These checks cannot be complete, but check for things which # will definitely cause failure. logging.debug("Calling %s", com.CHECK_SETUP_SCRIPT) ret = Popen([com.CHECK_SETUP_SCRIPT]).wait() if ret: raise SystemExit(1) # validate service name try: com.validate_service_name(options.service_name) except ValueError as err: raise SystemExit(err) # check that the service exists service_props = config.get_service_props(options.service_name) if not service_props: parser.error(_("The specified service does not exist: %s\n") % options.service_name) # get the image_path from the service try: # set image to be a InstalladmImage object image = svc.AIService(options.service_name).image except KeyError: raise SystemExit(_("\nThe specified service does not have an " "image_path property.\n")) # ensure we are not passed bootargs for a SPARC as we do not # support that if options.boot_args and image.arch == "sparc": parser.error(_("Boot arguments not supported for SPARC clients.\n")) options.arch = image.arch logging.debug("options = %s", options) return options