Beispiel #1
0
    def runCommand(self):
        self.parseArgs(
            _("""
Associates an existing adminstrative user with a hardware or software profile.
"""))
        swprofile = self.getArgs().swprofile
        hwprofile = self.getArgs().hwprofile

        if swprofile and hwprofile:
            raise InvalidCliRequest(
                _('Only one of --software-profile and --hardware-profile'
                  ' can be specified.'))

        if not swprofile and not hwprofile:
            raise InvalidCliRequest(
                _('Either --software-profile or --hardware-profile must'
                  ' be specified.'))

        admin_username = self.getArgs().adminUsername

        if admin_username is None:
            raise InvalidCliRequest(_('Missing Admin Username'))

        if swprofile:
            profile = swprofile
            api = self.configureClient(SoftwareProfileWsApi)
        else:
            profile = hwprofile
            api = self.configureClient(HardwareProfileWsApi)

        api.addAdmin(profile, admin_username)
Beispiel #2
0
    def runCommand(self):
        self.parseArgs(_("""
    post-application-data --app-name=APPLICATIONNAME --data-file=DATAFILE

Description:
    The  post-application-data tool posts an XML file to the Tortuga Rule
    Engine web service as input for configured rules.
"""))
        application_name = self.getArgs().applicationName

        if not application_name:
            raise InvalidCliRequest(_('Missing application name.'))
        data_file = self.getArgs().dataFile

        if not data_file:
            raise InvalidCliRequest(_('Missing application data file.'))

        if not os.path.exists(data_file):
            raise FileNotFound(_('Invalid application data file: %s.') % data_file)

        f = open(data_file, 'r')
        application_data = f.read()
        f.close()

        if not len(application_data):
            raise InvalidCliRequest(_('Empty application data file.'))

        self.get_rule_api().postApplicationData(application_name,
                                                application_data)
Beispiel #3
0
    def getAdminUsernameAndPassword(self):
        adminUsername = self.getArgs().adminUsername
        adminPassword = self.getArgs().adminPassword

        if not adminUsername:
            raise InvalidCliRequest(_('Missing Admin User Name.'))

        if not adminPassword:
            raise InvalidCliRequest(_('Missing Admin Password.'))

        return adminUsername, adminPassword
Beispiel #4
0
    def getApplicationNameAndRuleName(self):
        applicationName = self._options.applicationName
        ruleName = self._options.ruleName

        if not applicationName:
            raise InvalidCliRequest(_('Missing application name.'))

        if not ruleName:
            raise InvalidCliRequest(_('Missing rule name.'))

        return applicationName, ruleName
Beispiel #5
0
    def runCommand(self):
        self.parseArgs('''
Marks active node idle which will cause varying
actions based on the resource adapter associated with the given node.
''')

        # The "--node nodeName" option was implemented first
        # and we maintain backwards compatability for it.
        # The "nodeName..." arguments were added later.

        node_api = NodeWsApi(username=self.getUsername(),
                             password=self.getPassword(),
                             baseurl=self.getUrl(),
                             verify=self._verify)

        try:
            results = node_api.idleNode(self.getArgs().nodeName)

            if results['NodeAlreadyIdle']:
                print(_('The following node(s) are already in idle state:'))
                print('\n'.join(results['NodeAlreadyIdle']))

            if results['NodeSoftwareProfileLocked']:
                print(
                    _('The following node(s) are locked and cannot be idled:'))
                print('\n'.join(results['NodeSoftwareProfileLocked']))

        except Exception as msg:
            raise InvalidCliRequest(_("Can't idle node(s): {}").format(msg))
    def runCommand(self):
        self.parseArgs(
            _("""
    execute-rule --app-name=APPNAME --rule-name=RULENAME [--data-file=DATAFILE]

Description:
    The execute-rule tool forces execution of a given rule in the Tortuga Rule
    Engine.
"""))
        application_name, rule_name = self.getApplicationNameAndRuleName()
        data_file = self.getOptions().dataFile
        application_data = ''
        if data_file:
            if not os.path.exists(data_file):
                raise FileNotFound(
                    _('Invalid application data file: {}').format(data_file))
            else:
                f = open(data_file, 'r')
                application_data = f.read()
                f.close()
                if not len(application_data):
                    raise InvalidCliRequest(_('Empty application data file.'))

        self.get_rule_api().executeRule(application_name, rule_name,
                                        application_data)
        print(_('Executed rule {}/{}').format(application_name, rule_name))
Beispiel #7
0
    def getNetworkFromXml(self):
        """
        If the xmlFile option is present attempt to create a Network
        object from the xml.  Otherwise return None
        """

        network = None

        if self.getArgs().xmlFile:
            # An XML file was provided as input...start with that...
            f = open(self.getArgs().xmlFile, 'r')

            try:
                xmlString = f.read()
            finally:
                f.close()

            try:
                from tortuga.objects.network import Network
                network = Network.getFromXml(xmlString)
            except Exception as ex:  # pylint: disable=W0703
                self.getLogger().debug('Error parsing xml %s' % ex)

            if network is None:
                raise InvalidCliRequest(
                    _('File [%s] does not contain a valid network.') %
                    (self.getArgs().xmlFile))

        return network
Beispiel #8
0
    def runCommand(self):
        self.parseArgs(_('Remove network from the system'))

        # Parse --network argument if it exists
        networkAddress, networkSubnet = self.parseNetworkParameter(
            self.getArgs().network)

        # If we don't have a network and a netmask its an error
        if networkAddress is not None and networkSubnet is not None:
            network = self.getNetworkApi().getNetwork(
                networkAddress, networkSubnet)
        else:
            raise InvalidCliRequest(
                _('--network argument must be specified.'))

        # Delete the network
        try:
            self.getNetworkApi().deleteNetwork(network.getId())
        except DeleteNetworkFailed as ex:
            raise NetworkInUse(
                _('Unable to delete network [{0}].\nReason: {1}').format(
                    network, ex))
        except NetworkInUse:
            raise NetworkInUse(
                _('Network [{0}] contains nodes.  It cannot be'
                  ' deleted.').format(network))
Beispiel #9
0
    def runCommand(self):
        self.parseArgs()

        options = self.getArgs()

        if options.state and (options.bNotInstalled or options.bInstalled):
            raise InvalidCliRequest(
                '--state and --installed/--not-installed arguments are'
                ' mutually exclusive')

        api = NodeWsApi(username=self.getUsername(),
                        password=self.getPassword(),
                        baseurl=self.getUrl(),
                        verify=self._verify)

        nodes: List[Dict[str, Any]] = [
            dict(x) for x in api.getNodeList(nodespec=options.nodeName,
                                             tags=options.tags)
        ]

        if not nodes:
            if options.nodeName:
                print('No nodes matching nodespec [{}]\n'.format(
                    options.nodeName))

            sys.exit(1)

        if options.bInstalled:
            nodes = self.__filter_nodes(nodes, 'state', 'Installed')

        if options.bNotInstalled:
            nodes = self.__filter_nodes(nodes, 'state', 'Installed', True)

        if options.state:
            nodes = self.__filter_nodes(nodes, 'state', options.state)

        if options.softwareProfile:
            nodes = self.__filter_nodes(nodes, ['softwareprofile', 'name'],
                                        options.softwareProfile)

        if options.hardwareProfile:
            nodes = self.__filter_nodes(nodes, ['hardwareprofile', 'name'],
                                        options.hardwareProfile)

        if not options.showAll:
            nodes = self.__filter_nodes(nodes, 'state', 'Deleted', True)

        grouped: Dict[str, List[Dict[str, Any]]] = self.__group_nodes(
            nodes, options.bByHardwareProfile)

        if options.bShortOutput:
            output: Optional[str] = self.__make_short_output(grouped)
        elif options.bListOutput:
            output: Optional[str] = self.__make_list_output(nodes)
        else:
            output: Optional[str] = self.__make_full_output(grouped)

        if output:
            print(output)
Beispiel #10
0
    def runCommand(self):
        self.parseArgs(_('Shuts down the given node'))

        try:
            # Perform a "soft" shutdown
            NodeWsApi(username=self.getUsername(),
                      password=self.getPassword(),
                      baseurl=self.getUrl(),
                      verify=self._verify).shutdownNode(
                          self.getArgs().nodeName, True)
        except Exception as msg:
            raise InvalidCliRequest(_("Can't shutdown node(s) - %s") % (msg))
Beispiel #11
0
    def runCommand(self):
        self.parseArgs(_('Shuts down the given node'))

        api = self.configureClient(NodeWsApi)

        try:
            # Perform a "soft" shutdown
            api.shutdownNode(self.getArgs().nodeName, True)

        except Exception as msg:
            raise InvalidCliRequest(
                _("Can't shutdown node(s) - %s") % (msg))
Beispiel #12
0
    def validateNetwork(self, network):  # pylint: disable=no-self-use
        """
        Verify a network object has the minimum populated fields needed to
        add it to the database
        """

        if not network.getAddress():
            raise InvalidCliRequest(_('Network address must be specified.'))

        if not network.getNetmask():
            raise InvalidCliRequest(_('Subnet mask must be specified.'))

        if not network.getType():
            raise InvalidCliRequest(_('Network type must be specified.'))

        if network.getUsingDhcp() is None:
            raise InvalidCliRequest(
                _('Address allocation must be specified as DHCP or'
                  ' static.'))

        if network.getIncrement():
            increment = network.getIncrement()
            try:
                value = int(increment)
                if value < 1:
                    raise InvalidCliRequest(_('Increment must be positive.'))
            except ValueError:
                raise InvalidCliRequest(
                    _('Increment must be a positive integer.'))
Beispiel #13
0
    def __call__(self, parser, namespace, values, option_string=None):
        osValues = values.split('-', 3)

        if len(osValues) != 3:
            raise InvalidCliRequest(
                _('Error: Incorrect operating system specification.'
                  '\n\n--os argument should be in'
                  ' OSNAME-OSVERSION-OSARCH format'))

        name = osValues[0]
        version = osValues[1]
        arch = osValues[2]

        setattr(namespace, 'osInfo', OsInfo(name, version, arch))
Beispiel #14
0
    def runCommand(self):
        self.parseArgs(
            _("""
Associates an existing adminstrative user with a hardware or software profile.
"""))
        swprofile = self.getArgs().swprofile
        hwprofile = self.getArgs().hwprofile

        if swprofile and hwprofile:
            raise InvalidCliRequest(
                _('Only one of --software-profile and --hardware-profile'
                  ' can be specified.'))

        if not swprofile and not hwprofile:
            raise InvalidCliRequest(
                _('Either --software-profile or --hardware-profile must'
                  ' be specified.'))

        admin_username = self.getArgs().adminUsername

        if admin_username is None:
            raise InvalidCliRequest(_('Missing Admin Username'))

        if swprofile:
            profile = swprofile
            api = SoftwareProfileWsApi(username=self.getUsername(),
                                       password=self.getPassword(),
                                       baseurl=self.getUrl(),
                                       verify=self._verify)
        else:
            profile = hwprofile
            api = HardwareProfileWsApi(username=self.getUsername(),
                                       password=self.getPassword(),
                                       baseurl=self.getUrl(),
                                       verify=self._verify)

        api.addAdmin(profile, admin_username)
Beispiel #15
0
    def runCommand(self):
        self.parseArgs(
            _("""
    add-rule --desc-file=DESCRIPTIONFILE

Description:
    The add-rule tool adds a rule to the Tortuga Simple Policy Engine.
"""))

        if not self.getOptions().descriptionFile:
            raise InvalidCliRequest(_('Missing required --desc-file argument'))

        parser = RuleObjectFactory().getParser()
        rule = parser.parse(self.getOptions().descriptionFile)
        self.get_rule_api().addRule(rule)
Beispiel #16
0
    def assertIp(self, ip, parameterName, errorMsg=None):         \
            # pylint: disable=no-self-use
        """
        Convienience function for testing IPs and raising a configurable
        exception if the IP is invalid.
        """

        if errorMsg is None:
            errorMsg = _('The %s parameter must be a valid IP address.') % (
                parameterName)

        try:
            ipaddress.IPv4Address(str(ip))
        except ipaddress.AddressValueError:
            raise InvalidCliRequest(errorMsg)
Beispiel #17
0
    def parseNetworkParameter(self, network):         \
            # pylint: disable=no-self-use
        """
        Validator for the --network parameter.
        """

        try:
            result = ipaddress.IPv4Network(str(network))
        except ipaddress.AddressValueError:
            # Invalid argument to --network specified
            raise InvalidCliRequest(
                _('--network argument must be formatted as '
                  ' XXX.XXX.XXX.XXX/YY or XXX.XXX.XXX.XXX/YYY.YYY.YYY.YYY'))

        return result.network_address.exploded, result.netmask.exploded
Beispiel #18
0
    def runCommand(self):
        self.parseArgs()

        # Turn user input into a list
        destinationList = [
            node.strip()
            for node in self.getArgs().destinationString.split(',')
        ] if self.getArgs().destinationString else []

        api = self.configureClient(NodeWsApi)
        try:
            api.startupNode(self.getArgs().nodeName, destinationList,
                            self.getArgs().bootMethod)

        except Exception as msg:
            raise InvalidCliRequest(_("Unable to start node(s) - %s") % (msg))
Beispiel #19
0
    def runCommand(self):
        self.parseArgs(_('Get details of a specific network.'))

        # Parse --network parameter if it exists
        networkAddress, networkMask = self.parseNetworkParameter(
            self.getArgs().network)

        # If we don't have a network and a netmask its an error
        if networkAddress is not None and networkMask is not None:
            network = self.getNetworkApi().getNetwork(
                networkAddress, networkMask)
        else:
            raise InvalidCliRequest(
                _('The --network parameter must be specified.'))

        # TODO: do not output XML
        print(network.getXmlRep())
Beispiel #20
0
    def runCommand(self):
        self._logger.info('=' * 75)
        self._logger.info('Installation started')
        self._logger.info('=' * 75)

        self.parseArgs(_("""
tortuga-setup is run after the installation of the Tortuga software
in order to configure the base cluster environment.
"""))

        self._logger.info('command-line args: %s' % (' '.join(sys.argv[1:])))

        if self.getArgs().responseFile:
            if not os.path.exists(self.getArgs().responseFile):
                raise InvalidCliRequest(
                    'Response file [%s] does not exist' % (
                        self.getArgs().responseFile))

        tortuga_cfg = {}

        if self.getArgs().responseFile:
            tortuga_cfg['inifile'] = self.getArgs().responseFile

        tortuga_cfg['acceptEula'] = self.getArgs().acceptEula
        tortuga_cfg['force'] = self.getArgs().force
        tortuga_cfg['defaults'] = self.getArgs().defaults
        tortuga_cfg['consoleLogLevel'] = self.getArgs().consoleLogLevel

        if self.getArgs().skip_kits:
            tortuga_cfg['skip_kits'] = self.getArgs().skip_kits

        try:
            tortugaDeployer.TortugaDeployer(
                self._logger, cmdline_options=tortuga_cfg).runSetup()

            self._logger.info('=' * 75)
            self._logger.info('Installation completed successfully')
            self._logger.info('=' * 75)

        except TortugaException:
            self._logger.info('=' * 75)
            self._logger.info('Installation failed')
            self._logger.info('=' * 75)

            raise
Beispiel #21
0
    def runCommand(self):
        self.parseArgs()

        # Turn user input into a list
        destinationList = [
            node.strip()
            for node in self.getArgs().destinationString.split(',')
        ] if self.getArgs().destinationString else []

        try:
            NodeWsApi(username=self.getUsername(),
                      password=self.getPassword(),
                      baseurl=self.getUrl(),
                      verify=self._verify).startupNode(
                          self.getArgs().nodeName, destinationList,
                          self.getArgs().bootMethod)
        except Exception as msg:
            raise InvalidCliRequest(_("Unable to start node(s) - %s") % (msg))
Beispiel #22
0
    def runCommand(self):
        self.parseArgs(
            _("""
Reboots specified node(s). Mark nodes for reinstallation if --reinstall
flag is specified.
"""))

        nodeApi = self.configureClient(NodeWsApi)

        # If the node is being reinstalled as a result of the reboot,
        # do not use a soft shutdown.
        bSoftReboot = not self.getArgs().bReinstall

        try:
            nodeApi.rebootNode(self.getArgs().nodeSpec,
                               bSoftReboot,
                               bReinstall=self.getArgs().bReinstall)
        except Exception as msg:
            raise InvalidCliRequest(_("Can't reboot node(s) - %s") % (msg))
Beispiel #23
0
    def runCommand(self):
        self.parseArgs(
            _("""
Reboots specified node(s). Mark nodes for reinstallation if --reinstall
flag is specified.
"""))

        nodeApi = NodeWsApi(username=self.getUsername(),
                            password=self.getPassword(),
                            baseurl=self.getUrl(),
                            verify=self._verify)

        # If the node is being reinstalled as a result of the reboot,
        # do not use a soft shutdown.
        bSoftReboot = not self.getArgs().bReinstall

        try:
            nodeApi.rebootNode(self.getArgs().nodeSpec,
                               bSoftReboot,
                               bReinstall=self.getArgs().bReinstall)
        except Exception as msg:
            raise InvalidCliRequest(_("Can't reboot node(s) - %s") % (msg))
    def load_software_profile_template(self, tmplpath: str) -> dict:
        """
        Raises:
            InvalidProfileCreationTemplate
            InvalidCliRequest
        """

        # load from template
        if tmplpath and not os.path.exists(tmplpath):
            raise InvalidCliRequest(
                _('Cannot read software profile template [%s]') % (tmplpath))

        try:
            with open(tmplpath) as fp:
                result = json.load(fp)

                if 'softwareprofile' not in result:
                    raise InvalidProfileCreationTemplate(
                        'Missing \"softwareprofile\" envelope')

                return result['softwareprofile']
        except Exception as exc:
            raise InvalidProfileCreationTemplate(
                'Invalid software profile template: {}'.format(exc))
Beispiel #25
0
    def runCommand(self):
        self.parseArgs(usage=_("""
Updates software profile in the Tortuga system.
"""))

        if not self.getArgs().name and \
                not self.getArgs().softwareProfileName:
            self.getParser().error(
                'the following arguments are required: NAME'
            )

        if self.getArgs().name and self.getArgs().softwareProfileName:
            self.getParser().error(
                'argument name: not allowed with argument --name'
            )

        name = self.getArgs().name \
            if self.getArgs().name else self.getArgs().softwareProfileName

        api = SoftwareProfileWsApi(username=self.getUsername(),
                                   password=self.getPassword(),
                                   baseurl=self.getUrl(),
                                   verify=self._verify)

        sp = api.getSoftwareProfile(name, UpdateSoftwareProfileCli.optionDict)

        if self.getArgs().new_name is not None:
            sp.setName(self.getArgs().new_name)

        if self.getArgs().description is not None:
            sp.setDescription(self.getArgs().description)

        if self.getArgs().kernel is not None:
            sp.setKernel(self.getArgs().kernel)

        if self.getArgs().kernelParameters is not None:
            sp.setKernelParams(self.getArgs().kernelParameters)

        if self.getArgs().initrd is not None:
            sp.setInitrd(self.getArgs().initrd)

        if self.getArgs().unlock:
            if self.getArgs().soft_locked is not None:
                raise InvalidCliRequest(
                    '--soft-locked/--hard-locked arguments and --unlock'
                    ' argument are mutually exclusive'
                )

            sp.setLockedState('Unlocked')

        if self.getArgs().soft_locked is not None:
            sp.setLockedState(
                'SoftLocked' if self.getArgs().soft_locked else 'HardLocked')

        if self.getArgs().min_nodes is not None:
            # update min_nodes value
            try:
                if self.getArgs().min_nodes.lower() == 'none':
                    min_nodes = -1
                else:
                    min_nodes = int(self.getArgs().min_nodes)
            except ValueError:
                raise InvalidCliRequest(
                    'Invalid argument value for --min-nodes')

            sp.setMinNodes(min_nodes)
        else:
            min_nodes = sp.getMinNodes()

        if self.getArgs().max_nodes:
            try:
                max_nodes = -1 \
                    if self.getArgs().max_nodes.lower() == 'none' else \
                    int(self.getArgs().max_nodes)
            except ValueError:
                raise InvalidCliRequest(
                    'Invalid argument value for --max-nodes'
                )

            # update maxNodes value
            if max_nodes < min_nodes:
                # do not allow max nodes to be less than min nodes
                raise InvalidCliRequest(
                    'Maximum number of allowed nodes must be greater or equal'
                    ' to the mininum number of required nodes'
                )

            sp.setMaxNodes(max_nodes)

        if self.getArgs().deletePartition is not None:

            out = TortugaObjectList()
            for p in sp.getPartitions():
                for dp in self.getArgs().deletePartition:
                    if dp == p.getName():
                        # Skip over this item..its getting deleted
                        break
                else:
                    # Not a partition we are deleting
                    out.append(p)
            sp.setPartitions(out)

        partitionObject = None
        if self.getArgs().updatePartition:
            if self.getArgs().addPartition:
                raise InvalidCliRequest(
                    _('Must provide only one of --update-partition and'
                      ' --add-partition'))

            for p in sp.getPartitions():
                if p.getName() == self.getArgs().updatePartition:
                    partitionObject = p
                    break
            else:
                raise InvalidCliRequest(
                    _('Cannot update non-existent partition "%s"') % (
                        self.getArgs().updatePartition))

        if self.getArgs().addPartition:
            from tortuga.objects.partition import Partition
            partitionObject = Partition()
            partitionObject.setName(self.getArgs().addPartition)
            sp.getPartitions().append(partitionObject)
            if self.getArgs().device is None or \
                    self.getArgs().fileSystem is None or \
                    self.getArgs().size is None:
                raise InvalidCliRequest(
                    _('--device, --file-system, and --size options required'
                      ' with --add-partition'))

        if self.getArgs().grow:
            if not partitionObject:
                raise InvalidCliRequest(
                    _('The --grow/--no-grow options is only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setGrow(self.getArgs().grow)

        if self.getArgs().maxsize:
            if not partitionObject:
                raise InvalidCliRequest(
                    _('The --max-size option is only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setMaxSize(self.getArgs().maxsize)

        if self.getArgs().device is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('The --device option is only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setDevice(self.getArgs().device)

        if self.getArgs().mountPoint is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--mount-point option only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setMountPoint(self.getArgs().mountPoint)

        if self.getArgs().fileSystem is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('The --file-system option only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setFsType(self.getArgs().fileSystem)

        if self.getArgs().size is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--size option only allowed with --update-partition or'
                      ' --add-partition'))

            partitionObject.setSize(self._parseDiskSize(self.getArgs().size))

        if self.getArgs().options is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--options option only allowed with --update-partition'
                      ' or --add-partition'))

            partitionObject.setOptions(self.getArgs().options)

        if self.getArgs().directAttachment is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--direct-attachment option only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setDirectAttachment(
                self.getArgs().directAttachment)

        if self.getArgs().indirectAttachment is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--indirect-attachment option only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setIndirectAttachment(
                self.getArgs().indirectAttachment)

        if self.getArgs().diskSize is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--disk-size option only allowed with'
                      ' --update-partition or --add-partition'))

            try:
                partitionObject.setDiskSize(
                    self._parseDiskSize(self.getArgs().diskSize))
            except ValueError:
                raise InvalidCliRequest(_('Invalid --disk-size argument'))

        if self.getArgs().sanVolume is not None:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--san-volume option only allowed with'
                      ' --update-partition or --add-partition'))

            partitionObject.setSanVolume(self.getArgs().sanVolume)

        if self.getArgs().preserve is None:
            if self.getArgs().addPartition is not None:
                raise InvalidCliRequest(
                    _('--preserve or --no-preserve must be specified when'
                      ' adding a new partition.'))
        else:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--preserve and --no-preserve options are only allowed'
                      ' with --update-partition or --add-partition'))

            partitionObject.setPreserve(self.getArgs().preserve)

        if self.getArgs().bootLoader is None:
            if self.getArgs().addPartition is not None:
                raise InvalidCliRequest(
                    _('--boot-loader or --no-boot-loader must be specified'
                      ' when adding a new partition.'))
        else:
            if partitionObject is None:
                raise InvalidCliRequest(
                    _('--boot-loader and --no-boot-loader options only'
                      ' allowed with --update-partition or --add-partition'))

            partitionObject.setBootLoader(self.getArgs().bootLoader)

        if self.getArgs().tags:
            tags = sp.getTags()
            tags.update(parse_tags(self.getArgs().tags))
            sp.setTags(tags)
            print(tags)  # DEBUG

        if self.getArgs().remove_tags:
            tags = sp.getTags()
            for string in self.getArgs().remove_tags:
                for tag_name in string.split(','):
                    if tag_name in tags.keys():
                        tags.pop(tag_name)
            sp.setTags(tags)
            print(tags)  # DEBUG

        if self.getArgs().dataRoot is not None:
            sp.setDataRoot(self.getArgs().dataRoot)

        if self.getArgs().dataRsync is not None:
            sp.setDataRsync(self.getArgs().dataRsync)

        api.updateSoftwareProfile(sp)
Beispiel #26
0
    def _addNic(self, session, nicName):
        # Get IP address and netmask using facter

        facterNicName = nicName.replace(':', '_').replace('.', '_')

        entries = [
            'ipaddress_%s' % (facterNicName),
            'netmask_%s' % (facterNicName),
            'macaddress_%s' % (facterNicName),
            'network_%s' % (facterNicName)
        ]

        d = self._getMultipleFacterEntries(entries)

        if not 'ipaddress_%s' % (facterNicName) in d or \
           not d['ipaddress_%s' % (facterNicName)]:
            if not self.getArgs().ipaddress:
                raise InvalidCliRequest(
                    'Unable to determine IP address, use command-line'
                    ' override')

            ipaddress = self.getArgs().ipaddress
        else:
            ipaddress = d['ipaddress_%s' % (facterNicName)]

        if not 'netmask_%s' % (facterNicName) in d or \
           not d['netmask_%s' % (facterNicName)]:
            if not self.getArgs().netmask:
                raise InvalidCliRequest(
                    'Unable to determine netmask, use command-line'
                    ' override')

            netmask = self.getArgs().netmask
        else:
            netmask = d['netmask_%s' % (facterNicName)]

        if not 'network_%s' % (facterNicName) in d or \
           not d['network_%s' % (facterNicName)]:
            if not self.getArgs().network:
                raise InvalidCliRequest(
                    'Unable to determine network, use command-line'
                    ' override')

            network = self.getArgs().network
        else:
            network = d['network_%s' % (facterNicName)]

        # Check if nic is the default gateway as well...
        self._check_default_gateway_nic(nicName)

        dbNetwork = None

        # Attempt to find matching network
        try:
            dbNetwork = session.query(Network).filter(
                and_(Network.address == network,
                     Network.netmask == netmask)).one()

            print('Found network [%s/%s]' %
                  (dbNetwork.address, dbNetwork.netmask))
        except NoResultFound:
            # Network is not known to Tortuga, add it
            pass

        if dbNetwork is None:
            print('Adding network [%s/%s]' % (network, netmask))

            dbNetwork = self._addNetwork(nicName, network, netmask, session)

        # Attempt to find entry in NetworkDevices
        dbNetworkDevice = self._getNetworkDevice(nicName, session)
        if not dbNetworkDevice:
            # Create network device
            print('Adding network device [%s] as provisioning NIC' % (nicName))

            dbNetworkDevice = self._addNetworkDevice(nicName, session)
        else:
            print('Found existing network device [%s]' % (nicName))

        dbNode = NodesDbHandler().getNode(session, self._cm.getInstaller())

        # Attempt to find Nics entry
        for dbNic in dbNode.nics:
            if dbNic.networkdevice.name == nicName.lower():
                print('Found existing NIC entry for [%s]' %
                      (dbNic.networkdevice.name))

                break
        else:
            print('Creating NIC entry for [%s]' % (dbNetworkDevice.name))

            dbNic = Nic()
            dbNic.networkdevice = dbNetworkDevice
            dbNic.ip = ipaddress
            dbNic.boot = True
            dbNic.network = dbNetwork

            dbNode.nics.append(dbNic)

        # Attempt to find NIC association with hardware profile (commonly
        # known as hardware profile provisioning NIC)
        for dbHwProfileNic in dbNode.hardwareprofile.nics:
            if dbHwProfileNic == dbNic:
                break
        else:
            print('Adding NIC [%s] to hardware profile [%s]' %
                  (dbNic.networkdevice.name, dbNode.hardwareprofile.name))

            dbNode.hardwareprofile.nics.append(dbNic)

        # Attempt to find 'HardwareProfileNetworks' entry
        for dbHardwareProfileNetwork in \
                dbNode.hardwareprofile.hardwareprofilenetworks:
            if dbHardwareProfileNetwork.network == dbNetwork and \
                dbHardwareProfileNetwork.networkdevice == dbNetworkDevice:
                print('Found existing hardware profile/network association')
                break
        else:
            dbHardwareProfileNetwork = HardwareProfileNetwork()

            dbHardwareProfileNetwork.network = dbNetwork
            dbHardwareProfileNetwork.networkdevice = dbNetworkDevice

            dbNode.hardwareprofile.hardwareprofilenetworks.append(
                dbHardwareProfileNetwork)

        session.commit()

        bUpdated = self._updateNetworkConfig(session, dbNode)

        if bUpdated and self.getArgs().bSync:
            print('Applying changes to Tortuga...')

            cmd = ('/opt/puppetlabs/bin/puppet agent --onetime'
                   ' --no-daemonize >/dev/null 2>&1')
            tortugaSubprocess.executeCommandAndIgnoreFailure(cmd)
Beispiel #27
0
    def runCommand(self):
        self.parseArgs()

        if self.getArgs().name and self.getArgs().deprecated_name:
            self.getParser().error(
                'argument name: not allowed with argument --name')

        name = self.getArgs().name \
            if self.getArgs().name else self.getArgs().deprecated_name

        if self.getArgs().jsonTemplatePath:
            # load from template
            if self.getArgs().jsonTemplatePath and \
                    not os.path.exists(self.getArgs().jsonTemplatePath):
                raise InvalidCliRequest(
                    _('Cannot read template from %s') %
                    (self.getArgs().jsonTemplatePath))

            try:
                with open(self.getArgs().jsonTemplatePath) as fp:
                    buf = json.load(fp)

                tmpl_dict = buf['hardwareProfile']
            except Exception as exc:
                raise InvalidProfileCreationTemplate(
                    'Invalid profile creation template: {}'.format(exc))
        else:
            tmpl_dict = {}

        # build up dict from scratch
        if name:
            tmpl_dict['name'] = name

        if self.getArgs().description:
            tmpl_dict['description'] = self.getArgs().description

        if hasattr(self.getArgs(), 'osInfo'):
            tmpl_dict['os'] = {
                'name': getattr(self.getArgs(), 'osInfo').getName(),
                'version': getattr(self.getArgs(), 'osInfo').getVersion(),
                'arch': getattr(self.getArgs(), 'osInfo').getArch(),
            }

        if self.getArgs().nameFormat:
            tmpl_dict['nameFormat'] = self.getArgs().nameFormat

        elif 'nameFormat' not in tmpl_dict:
            tmpl_dict['nameFormat'] = 'compute-#NN'

        if self.getArgs().tags:
            tmpl_dict['tags'] = parse_tags(self.getArgs().tags)

        settings_dict = {
            'defaults':
            self.getArgs().bUseDefaults,
            'osInfo':
            getattr(self.getArgs(), 'osInfo') if hasattr(
                self.getArgs(), 'osInfo') else None,
        }

        hw_profile_spec = HardwareProfile.getFromDict(tmpl_dict)

        api = HardwareProfileWsApi(username=self.getUsername(),
                                   password=self.getPassword(),
                                   baseurl=self.getUrl(),
                                   verify=self._verify)

        api.createHardwareProfile(hw_profile_spec, settings_dict)
Beispiel #28
0
    def runCommand(self):
        self.parseArgs()

        if not self.getArgs().name and \
                not self.getArgs().hardwareProfileName:
            self.getParser().error(
                'the following arguments are required: NAME')

        if self.getArgs().name and self.getArgs().hardwareProfileName:
            self.getParser().error(
                'argument name: not allowed with argument --name')

        name = self.getArgs().name \
            if self.getArgs().name else self.getArgs().hardwareProfileName

        api = HardwareProfileWsApi(username=self.getUsername(),
                                   password=self.getPassword(),
                                   baseurl=self.getUrl(),
                                   verify=self._verify)

        spApi = SoftwareProfileWsApi(username=self.getUsername(),
                                     password=self.getPassword(),
                                     baseurl=self.getUrl(),
                                     verify=self._verify)

        nodeApi = NodeWsApi(username=self.getUsername(),
                            password=self.getPassword(),
                            baseurl=self.getUrl(),
                            verify=self._verify)

        hp = api.getHardwareProfile(name, UpdateHardwareProfileCli.optionDict)

        if self.getArgs().newName is not None:
            hp.setName(self.getArgs().newName)

        if self.getArgs().description is not None:
            hp.setDescription(self.getArgs().description)

        if self.getArgs().nameFormat is not None:
            hp.setNameFormat(self.getArgs().nameFormat)

        if self.getArgs().kernel is not None:
            hp.setKernel(self.getArgs().kernel)

        if self.getArgs().kernelParameters is not None:
            hp.setKernelParams(self.getArgs().kernelParameters)

        if self.getArgs().initrd is not None:
            hp.setInitrd(self.getArgs().initrd)

        if self.getArgs().soAllowed is not None:
            if self.getArgs().soAllowed.lower() == _('true'):
                hp.setSoftwareOverrideAllowed(True)
            elif self.getArgs().soAllowed.lower() == _('false'):
                hp.setSoftwareOverrideAllowed(False)
            else:
                raise InvalidCliRequest(
                    _('--software-override-allowed must be either "true" or'
                      ' "false".'))

        if self.getArgs().idleProfile is not None and \
           self.getArgs().bUnsetIdleProfile:
            raise InvalidCliRequest(
                _('Conflicting options --idle-software-profile and'
                  ' --unset-idle-software-profile'))

        if self.getArgs().idleProfile is not None:
            sp = spApi.getSoftwareProfile(self.getArgs().idleProfile)

            hp.setIdleSoftwareProfileId(sp.getId())

        if self.getArgs().bUnsetIdleProfile:
            hp.setIdleSoftwareProfileId(None)

        if self.getArgs().location is not None:
            hp.setLocation(self.getArgs().location)

        if self.getArgs().localBootParameters is not None:
            hp.setLocalBootParams(self.getArgs().localBootParameters)

        if self.getArgs().cost is not None:
            hp.setCost(self.getArgs().cost)

        if self.getArgs().resourceAdapter:
            resourceAdapter = ResourceAdapter(
                name=self.getArgs().resourceAdapter)
            hp.setResourceAdapter(resourceAdapter)

        if self.getArgs().default_adapter_config:
            hp.setDefaultResourceAdapterConfig(
                self.getArgs().default_adapter_config)

        if self.getArgs().deletePNic is not None:
            out = TortugaObjectList()

            for nic in hp.getProvisioningNics():
                for dnic in self.getArgs().deletePNic:
                    if dnic == nic.getIp():
                        # Skip over this item..its getting deleted
                        break
                else:
                    # Not a NIC we are deleting
                    out.append(nic)

            hp.setProvisioningNics(out)

        if self.getArgs().addPNic is not None:
            for nicIp in self.getArgs().addPNic:
                nicsNode = nodeApi.getNodeByIp(nicIp)

                if nicsNode is not None:
                    for nic in nicsNode.getNics():
                        if nic.getIp() == nicIp:
                            hp.getProvisioningNics().append(nic)
                            break

        if self.getArgs().deleteNetwork is not None:
            # Make sure we actually delete a network
            out = TortugaObjectList()
            out.extend(hp.getNetworks())

            for netstring in self.getArgs().deleteNetwork:
                try:
                    dnet, dmask, ddev = netstring.split('/')
                except ValueError:
                    raise InvalidCliRequest(
                        _('Incorrect input format for --delete-network'
                          ' ("address/mask/device")'))

                for network in hp.getNetworks():
                    if dnet == network.getAddress() and \
                       dmask == network.getNetmask() and \
                       ddev == network.getNetworkDevice().getName():
                        # Skip over this item..its getting deleted
                        for n in out:
                            if n.getId() == network.getId():
                                out.remove(n)
                                break

                        break
                else:
                    # Not a NIC we are deleting
                    print('Ignoring deletion of non-existent network:'
                          ' %s/%s/%s' % (dnet, dmask, ddev))

            hp.setNetworks(out)

        if self.getArgs().addNetwork:
            for netstring in self.getArgs().addNetwork:
                try:
                    anet, amask, adev = netstring.split('/')
                except ValueError:
                    raise InvalidCliRequest(
                        _('Incorrect input format for --add-network'
                          ' ("address/mask/device")'))

                network = Network()
                networkDevice = NetworkDevice()
                networkDevice.setName(adev)
                network.setAddress(anet)
                network.setNetmask(amask)
                network.setNetworkDevice(networkDevice)
                hp.getNetworks().append(network)

        if self.getArgs().tags:
            tags = hp.getTags()
            tags.update(parse_tags(self.getArgs().tags))
            hp.setTags(tags)

        if self.getArgs().remove_tags:
            tags = hp.getTags()
            for string in self.getArgs().remove_tags:
                for tag_name in string.split(','):
                    if tag_name in tags.keys():
                        tags.pop(tag_name)
            hp.setTags(tags)

        api.updateHardwareProfile(hp)
Beispiel #29
0
    def updateNetwork(self, network):
        """
        Update a passed in network tortuga object with the values passed
        in on the command line.
        """

        # Check for conflicting command-line options
        if (self.getArgs().netmask or self.getArgs().address) and \
                self.getArgs().network:
            self.getParser().error(
                'Specify network using --network/--netmask or --network')

        if self.getArgs().network:
            # Use 'ipaddr' module to validate network spec
            parsed_network, parsed_netmask = \
                self.parseNetworkParameter(self.getArgs().network)

            network.setAddress(parsed_network)
            network.setNetmask(parsed_netmask)
        else:
            if self.getArgs().address is not None:
                self.assertIp(self.getArgs().address, '--address')
                network.setAddress(self.getArgs().address)

            if self.getArgs().netmask is not None:
                self.assertIp(self.getArgs().netmask, '--netmask')
                network.setNetmask(self.getArgs().netmask)

        if self.getArgs().suffix is not None:
            network.setSuffix(self.getArgs().suffix)

        if self.getArgs().gateway is not None:
            self.assertIp(self.getArgs().gateway, '--gateway')
            network.setGateway(self.getArgs().gateway)

        if self.getArgs().name is not None:
            network.setName(self.getArgs().name)

        if self.getArgs().startIp is not None:
            self.assertIp(self.getArgs().startIp, '--start-ip')
            network.setStartIp(self.getArgs().startIp)

        if self.getArgs().type is not None:
            network.setType(self.getArgs().type)

        if self.getArgs().increment is not None:
            network.setIncrement(self.getArgs().increment)

        optionsString = network.getOptions()
        optionsDict = {}
        if optionsString:
            # VLAN info may already exist for this network
            optionsList = optionsString.split(';')
            for originalOption in optionsList:
                key, value = originalOption.split('=')
                optionsDict[key] = value

        vlanIdFound = self.getArgs().vlanId is not None or \
            'vlan' in optionsDict

        vlanParentNetworkFound = \
            self.getArgs().vlanParentNetwork is not None or \
            'vlanparent' in optionsDict

        if (vlanIdFound and not vlanParentNetworkFound) or \
                (not vlanIdFound and vlanParentNetworkFound):
            raise InvalidCliRequest(
                _('--vlan-id and --vlan-parent-network must be used'
                  ' together.'))

        if self.getArgs().vlanId:
            optionsDict['vlan'] = self.getArgs().vlanId

        if self.getArgs().vlanParentNetwork:
            # Match the given parent network to a network in the DB
            networkAddr, subnetMask = self.parseNetworkParameter(
                self.getArgs().vlanParentNetwork)

            existingNetworkList = self.getNetworkApi().getNetworkList()

            matchingNetworkId = None

            for existingNetwork in existingNetworkList:
                if existingNetwork.getAddress() == networkAddr and \
                        existingNetwork.getNetmask() == subnetMask:
                    matchingNetworkId = existingNetwork.getId()

            if not matchingNetworkId:
                raise InvalidCliRequest(
                    _('Network [%s] not found') %
                    (self.getArgs().vlanParentNetwork))

            optionsDict['vlanparent'] = matchingNetworkId

        newOptions = ''

        if self.getArgs().vlanId or self.getArgs().vlanParentNetwork:
            for entry in list(optionsDict.items()):
                optionKey, optionValue = entry
                newOptions += '%s=%s;' % (optionKey, optionValue)

            # Take off the last semicolon
            newOptions = newOptions[:-1]

        if self.getArgs().options:
            if newOptions:
                newOptions = '%s;%s' % (newOptions, self.getArgs().options)
            else:
                newOptions = self.getArgs().options

        if self.getArgs().options or self.getArgs().vlanId or \
                self.getArgs().vlanParentNetwork:
            network.setOptions(newOptions)

        if self.getArgs().usingDhcp is not None:
            network.setUsingDhcp(self.getArgs().usingDhcp)