def runCommand(self):
        self.parseArgs(_('Create software profile'))

        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

        # load template if specified with '--template', otherwise build
        # template
        tmpl_dict = {} if not self.getArgs().jsonTemplatePath else \
            self.load_software_profile_template(
                self.getArgs().jsonTemplatePath)

        if name:
            tmpl_dict['name'] = name

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

        if self.getArgs().profileType:
            tmpl_dict['type'] = self.getArgs().profileType
        elif 'type' not in tmpl_dict:
            tmpl_dict['type'] = 'compute'

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

        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().dataRoot:
            tmpl_dict['dataRoot'] = self.getArgs().dataRoot

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

        sw_profile_spec = SoftwareProfile.getFromDict(tmpl_dict)

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

        # Populate 'settings_dict' from command-line arguments
        settings_dict = {
            'bOsMediaRequired': self.getArgs().bOsMediaRequired,
            'unmanagedProfile': self.getArgs().unmanaged,
        }

        api.createSoftwareProfile(sw_profile_spec, settings_dict)
Example #2
0
    def add_tag(self, session: Session, args):
        if not args.nodespec and not args.software_profile and \
                not args.hardware_profile:
            sys.stderr.write('Error: must specify --nodes'
                             '/--software-profile/--hardware-profile\n')
            sys.stderr.flush()
            sys.exit(1)

        tags = parse_tags(args.tags)

        if args.nodespec:
            nodes = self._node_api.getNodesByNameFilter(session, args.nodespec)
            for node in nodes:
                node_tags = node.getTags()
                node_tags.update(tags)
                self._node_api.set_tags(session,
                                        node_id=node.getId(),
                                        tags=node_tags)
                print(node.getName(), node.getTags())

        if args.software_profile:
            for name in args.software_profile.split(','):
                swp = self._swp_api.getSoftwareProfile(session, name)
                swp_tags = swp.getTags()
                swp_tags.update(tags)
                swp.setTags(swp_tags)
                self._swp_api.updateSoftwareProfile(session, swp)

        if args.hardware_profile:
            for name in args.hardware_profile.split(','):
                hwp = self._hwp_api.getHardwareProfile(session, name)
                hwp_tags = hwp.getTags()
                hwp_tags.update(tags)
                hwp.setTags(hwp_tags)
                self._hwp_api.updateHardwareProfile(session, hwp)

        session.commit()
Example #3
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)
Example #4
0
    def runCommand(self):
        self.parseArgs()

        # Validate options
        if self.getArgs().macImportFile:
            if self.getArgs().nodeCount:
                sys.stderr.write('Ignoring \'--count\' option when importing'
                                 ' from MAC file\n')

        addHostWsApi = self.configureClient(AddHostWsApi)

        addNodesRequest = {
            'force': self.getArgs().force,
        }

        if self.getArgs().hardwareProfileName:
            addNodesRequest['hardwareProfile'] = \
                self.getArgs().hardwareProfileName

        # Parse extra arguments
        extra_args = dict()

        for extra_arg in self.getArgs().extra_args or []:
            key, value = extra_arg.split('=', 1) \
                if '=' in extra_arg else (extra_arg, None)

            extra_args[key] = value

        if self.getArgs().extra_args and extra_args:
            addNodesRequest['extra_args'] = extra_args

        if not self.getArgs().macImportFile and \
                self.getArgs().nodeCount is not None:
            # Only set the node count if not importing from a file
            addNodesRequest['count'] = self.getArgs().nodeCount

        if self.getArgs().rackNumber is not None:
            addNodesRequest['rack'] = self.getArgs().rackNumber

        if self.getArgs().softwareProfileName:
            addNodesRequest['softwareProfile'] = \
                self.getArgs().softwareProfileName

        if not self.getArgs().hardwareProfileName and \
                not self.getArgs().softwareProfileName:
            self.getParser().error(
                '--software-profile or --hardware-profile and '
                ' --software-profile must be specified')

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

        if self.getArgs().data:
            addNodesRequest['data'] = self.getArgs().data

        nodeDetails = []

        if self.getArgs().macAddr or self.getArgs().ipAddress or \
                self.getArgs().hostName:
            if self.getArgs().nodeCount is not None:
                addNodesRequest['count'] = self.getArgs().nodeCount

            nics = self.__extract_nics(
                self.getArgs().ipAddress,
                self.getArgs().macAddr.lower()
                if self.getArgs().macAddr else None)

            nodeDetail = {}

            if nics:
                nodeDetail['nics'] = nics

                addNodesRequest['count'] = 1

            if self.getArgs().hostName:
                nodeDetail['name'] = self.getArgs().hostName

                addNodesRequest['count'] = 1

            nodeDetails.append(nodeDetail)
        else:
            if self.getArgs().macImportFile:
                if not os.path.exists(self.getArgs().macImportFile):
                    sys.stderr.write(
                        _('Error: file [%s] not found') %
                        (self.getArgs().macImportFile) + '\n')

                    raise SystemExit(1)

                # Parse input file
                with open(self.getArgs().macImportFile) as fd:
                    for line in fd.readlines():
                        if not line == '' and not line[0] == '#':
                            itemList = line.rstrip().split()
                            mac = ipAddr = hostname = None
                            for item in itemList:
                                # Definatly MAC
                                if not item.find(':') < 0:
                                    mac = item.lower()
                                # IP or hostname
                                elif not item.find('.') < 0:
                                    try:
                                        ipAddr = str(
                                            ipaddress.IPv4Address(item))
                                    except ipaddress.AddressValueError:
                                        # Unable to convert to dotted quad;
                                        # must be a host name
                                        hostname = item
                                else:
                                    hostname = item

                            nodeDetail = {}

                            if mac:
                                nodeDetail['mac'] = mac

                            if ipAddr:
                                nodeDetail['ip'] = ipAddr

                            if hostname:
                                nodeDetail['name'] = hostname

                            nodeDetails.append({'nics': [nodeDetail]})

        if nodeDetails:
            addNodesRequest['nodeDetails'] = nodeDetails

            if 'count' not in addNodesRequest:
                addNodesRequest['count'] = len(nodeDetails)

        if self.getArgs().resource_adapter_configuration:
            addNodesRequest['resource_adapter_configuration'] = \
                self.getArgs().resource_adapter_configuration

        try:
            addHostSession = addHostWsApi.addNodes(addNodesRequest)

            if self.getArgs().quiet:
                sys.stdout.write('{0}\n'.format(addHostSession))
            else:
                # Async (default) invocation; show user output
                sys.stdout.write(
                    'Add host session [{0}] created successfully.\n'
                    ' Use \'get-node-requests -r {0}\' to query request'
                    ' status\n'.format(addHostSession))

                sys.stdout.flush()
        except (UrlErrorException, HttpErrorException):
            sys.stderr.write(
                'Error: unable to communicate with Tortuga webservice.\n'
                '\nEnsure webservice is running. Check log(s)'
                ' for additional information.\n')

            raise SystemExit(1)
Example #5
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)
Example #6
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)