示例#1
0
 def get_routes_directiveformat(self, routecfg_path):
     """
     This method reads from routes file and contructs key,value information.
     for the below format.
     :param :route file path which has info in network directives format
     :return: dictionary consisting of route information read from file
     Ex:
     ADDRESS0=10.10.10.13
     NETMASK0=255.255.255.254
     GATEWAY0=10.10.10.15
     METRIC0=1
     """
     with open(routecfg_path, "r") as routecfg_file:
         line = routecfg_file.read()
         cfgroutes_info = {}
         route_input = line.split()
         for elem in route_input:
             try:
                 cfgroutes_info[elem.split('=')[0]] = elem.split('=')[1]
             except Exception, e:
                 raise OperationFailed("GINNET0030E", {'err': e.message})
示例#2
0
def change_dasdpart_type(part, type):
    """
    Change the type of the dasd partition
    :param part: name of the dasd partition e.g. dasd1
    :param type: partition type to be changed to e.g 4 (Linux LVM type)
    :return:
    """
    partnum = ''.join(filter(lambda x: x.isdigit(), part))
    typ_str = '\nt\n' + partnum + '\n' + type + '\n' + 'w\n'
    devname = ''.join(i for i in part if not i.isdigit())
    devname = '/dev/' + devname
    p1_out = subprocess.Popen(["echo", "-e", "\'", typ_str, "\'"],
                              stdout=subprocess.PIPE)
    p2_out = subprocess.Popen(["fdasd", devname], stdin=p1_out.stdout,
                              stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    p1_out.stdout.close()
    out, err = p2_out.communicate()
    if p2_out.returncode != 0:
        raise OperationFailed("GINDASDPAR0014E",
                              {'err': err})
    return
示例#3
0
    def getPackageInfo(self, pkg_name):
        """
        Get package information. The return is a dictionary containg the
        information about a package, in the format:

        package = {'package_name': <string>,
                   'version': <string>,
                   'arch': <string>,
                   'repository': <string>
                  }
        """
        self.wait_pkg_manager_available()

        package = {}
        try:
            self._apt_cache.open()
            self._apt_cache.upgrade()
            pkgs = self._apt_cache.get_changes()
            self._apt_cache.close()
        except Exception, e:
            raise OperationFailed('GGBPKGUPD0006E', {'err': e.message})
示例#4
0
    def create(self, vmid, params):
        dev_name = params['name']
        self._passthrough_device_validate(dev_name)
        dev_info = DeviceModel(conn=self.conn).lookup(dev_name)

        with RollbackContext() as rollback:
            try:
                dev = self.conn.get().nodeDeviceLookupByName(dev_name)
                dev.dettach()
            except Exception:
                raise OperationFailed('KCHVMHDEV0005E', {'name': dev_name})
            else:
                rollback.prependDefer(dev.reAttach)

            attach_device = getattr(
                self, '_attach_%s_device' % dev_info['device_type'])

            info = attach_device(vmid, dev_info)
            rollback.commitAll()

        return info
示例#5
0
    def _refreshUpdateList(self):
        """
        Update the list of packages to be updated in the system.
        """
        self._pkgs = []
        cmd = ["zypper", "list-updates"]
        (stdout, stderr, returncode) = run_command(cmd)

        if len(stderr) > 0:
            raise OperationFailed('GGBPKGUPD0003E', {'err': stderr})

        for line in stdout.split('\n'):
            if line.find('v |') >= 0:
                info = line.split(' | ')
                package = {
                    'package_name': info[2],
                    'version': info[4],
                    'arch': info[5],
                    'repository': info[1]
                }
                self._pkgs.append(package)
示例#6
0
    def fork_vm_storage(self, vm_uuid):
        # Provision storages:
        disk_and_vol_list = self.to_volume_list(vm_uuid)
        try:
            for v in disk_and_vol_list:
                if v['pool'] is not None:
                    pool = self._get_storage_pool(v['pool'])
                    # outgoing text to libvirt, decode('utf-8')
                    pool.createXML(v['xml'].decode('utf-8'), 0)
                else:
                    capacity = v['capacity']
                    format_type = v['format']
                    path = v['path']
                    create_disk_image(format_type=format_type,
                                      path=path,
                                      capacity=capacity)

        except libvirt.libvirtError as e:
            raise OperationFailed('KCHVMSTOR0008E', {'error': str(e)})

        return disk_and_vol_list
示例#7
0
    def getPackagesList(self):
        """
        Return a list of package's dictionaries. Each dictionary contains the
        information about a package, in the format:
        package = {'package_name': <string>, 'version': <string>,
                   'arch': <string>, 'repository': <string>}
        """
        if self.isRunning():
            raise OperationFailed('GGBPKGUPD0005E')

        self._refreshUpdateList()
        pkg_list = []
        for pkg in self._pkgs:
            package = {
                'package_name': pkg.name,
                'version': pkg.version,
                'arch': pkg.arch,
                'repository': pkg.ui_from_repo
            }
            pkg_list.append(package)
        return pkg_list
示例#8
0
    def getPackagesList(self):
        """
        Return a list of packages eligible to be updated by Zypper.
        """
        self.wait_pkg_manager_available()

        packages = []
        cmd = ["zypper", "list-updates"]
        (stdout, stderr, returncode) = run_command(cmd)

        if len(stderr) > 0:
            raise OperationFailed('GGBPKGUPD0003E', {'err': stderr})

        for line in stdout.split('\n'):
            if line.startswith('v |'):
                line = line.split(' | ')
                pkg = {'package_name': line[2].strip(),
                       'version': line[4].strip(), 'arch': line[5].strip(),
                       'repository': line[1].strip()}
                packages.append(pkg)
        return packages
示例#9
0
def create_disk_image(format_type, path, capacity):
    """
    Create a disk image for the Guest
    Args:
        format: Format of the storage. e.g. qcow2
        path: Path where the virtual disk will be created
        capacity: Capacity of the virtual disk in GBs

    Returns:

    """
    out, err, rc = run_command([
        "/usr/bin/qemu-img", "create", "-f", format_type, "-o",
        "preallocation=metadata", path,
        encode_value(capacity) + "G"
    ])

    if rc != 0:
        raise OperationFailed("KCHTMPL0041E", {'err': err})

    return
示例#10
0
 def _get_storagepool_vols_num(self, pool):
     try:
         if pool.isActive():
             pool.refresh(0)
             return pool.numOfVolumes()
         else:
             return 0
     except libvirt.libvirtError as e:
         # If something (say a busy pool) prevents the refresh,
         # throwing an Exception here would prevent all pools from
         # displaying information -- so return None for busy
         wok_log.error("ERROR: Storage Pool get vol count: %s " %
                       e.get_error_message())
         wok_log.error("ERROR: Storage Pool get vol count error no: %s " %
                       e.get_error_code())
         return 0
     except Exception as e:
         raise OperationFailed("KCHPOOL0008E", {
             'name': pool.name(),
             'err': e.get_error_message()
         })
示例#11
0
 def construct_rules(self, params):
     """
     Creates file system, system call rule and control rules.
     :param params: dict with rules params
     :return: the rule
     """
     try:
         rule = ''
         if params["type"] == "File System Rule":
             rule = '-w'
             rule = self.construct_fs_rule(rule, params)
         elif params["type"] == "System Call Rule":
             rule = '-a'
             rule = self.construct_sc_rule(rule, params)
         elif params["type"] == "Control Rule":
             rule = self.construct_control_rule(params)
         return rule
     except MissingParameter:
         raise
     except Exception as e:
         raise OperationFailed("GINAUD0003E", {'error': e.message})
示例#12
0
    def delete(self, name):
        if self._pool_used_by_template(name):
            raise InvalidOperation('KCHPOOL0035E', {'name': name})

        pool = self.get_storagepool(name, self.conn)
        if pool.isActive():
            raise InvalidOperation("KCHPOOL0005E", {'name': name})

        vms = self._get_vms_attach_to_storagepool(name)
        if len(vms) > 0:
            raise InvalidOperation('KCHPOOL0039E', {
                'name': name,
                'vms': ",".join(vms)
            })
        try:
            pool.undefine()
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHPOOL0011E", {
                'name': name,
                'err': e.get_error_message()
            })
示例#13
0
def run_systemd_command(command):
    """Function that runs systemd commands.

    Runs a systemd command specified in the argument, throwing
    a specific error if something goes wrong.

    Args:
        command (List[str]): the systemd command to be executed.

    Returns:
        str: Output of the command.

    Raises:
        OperationFailed if the return code of the command is not 0.

    """
    output, err, rcode = run_command(command)
    if rcode != 0:
        cmd_str = ' '.join(command)
        raise OperationFailed('GINSERV00001E', {'cmd': cmd_str, 'err': err})
    return output
示例#14
0
    def delete(self, pool, name):
        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})

        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        vol_path = volume.path()
        try:
            volume.delete(0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0010E", {
                'name': name,
                'err': e.get_error_message()
            })

        try:
            os.remove(vol_path)
        except OSError, e:
            wok_log.error("Unable to delete storage volume file: %s."
                          "Details: %s" % (pool_info['path'], e.message))
示例#15
0
    def create(self, vmid, params):
        dev_name = params['name']
        dev_info = self.dev_model.lookup(dev_name)

        if dev_info['device_type'] == 'pci':
            taskid = AsyncTask(
                u'/plugins/kimchi/vms/%s/hostdevs/' %
                VMModel.get_vm(vmid, self.conn).name(),
                self._attach_pci_device,
                {
                    'vmid': vmid,
                    'dev_info': dev_info,
                    'lock': threading.RLock()
                },
            ).id
            return self.task.lookup(taskid)

        with RollbackContext() as rollback:
            try:
                dev = self.conn.get().nodeDeviceLookupByName(dev_name)
                dev.dettach()
            except Exception:
                raise OperationFailed('KCHVMHDEV0005E', {'name': dev_name})
            else:
                rollback.prependDefer(dev.reAttach)

            rollback.commitAll()

        taskid = AsyncTask(
            u'/plugins/kimchi/vms/%s/hostdevs/' %
            VMModel.get_vm(vmid, self.conn).name(),
            '_attach_%s_device' % dev_info['device_type'],
            {
                'vmid': vmid,
                'dev_info': dev_info,
                'lock': threading.RLock()
            },
        ).id

        return self.task.lookup(taskid)
示例#16
0
def upgrade_objectstore_template_disks(libv_conn):
    """
        Upgrade the value of a given JSON's item of all Templates.
        Removes 'storagepool' entry and adds
        'pool: { name: ..., type: ... }'
    """
    total = 0
    try:
        conn = sqlite3.connect(config.get_object_store(), timeout=10)
        cursor = conn.cursor()
        sql = "SELECT id, json FROM objects WHERE type='template'"
        cursor.execute(sql)
        for row in cursor.fetchall():
            template = json.loads(row[1])

            # Get pool info
            pool_uri = template['storagepool']
            pool_name = pool_name_from_uri(pool_uri)
            pool = libv_conn.get().storagePoolLookupByName(
                pool_name.encode("utf-8"))
            pool_type = xpath_get_text(pool.XMLDesc(0), "/pool/@type")[0]

            # Update json
            new_disks = []
            for disk in template['disks']:
                disk['pool'] = {'name': pool_uri,
                                'type': pool_type}
                new_disks.append(disk)
            template['disks'] = new_disks
            del template['storagepool']

            sql = "UPDATE objects SET json=? WHERE id=?"
            cursor.execute(sql, (json.dumps(template), row[0]))
            conn.commit()
            total += 1
    except sqlite3.Error, e:
        if conn:
            conn.rollback()
        wok_log.error("Error while upgrading objectstore data: %s", e.args[0])
        raise OperationFailed("KCHUTILS0006E")
示例#17
0
    def update(self, vm_name, dev_name, params):
        old_disk_used_by = None
        new_disk_used_by = None

        dom = VMModel.get_vm(vm_name, self.conn)

        dev_info = self.lookup(vm_name, dev_name)
        if dev_info['type'] != 'cdrom':
            raise InvalidOperation('KCHVMSTOR0006E')

        params['path'] = params.get('path', '')
        old_disk_path = dev_info['path']
        new_disk_path = params['path']
        if new_disk_path != old_disk_path:
            # An empty path means a CD-ROM was empty or ejected:
            if old_disk_path != '':
                old_disk_used_by = get_disk_used_by(self.conn, old_disk_path)
            if new_disk_path != '':
                new_disk_used_by = get_disk_used_by(self.conn, new_disk_path)

        dev_info.update(params)
        dev, xml = get_disk_xml(dev_info)

        try:
            # FIXME: when updating from local file to remote file (http)
            # libvirt adds a new device with same name instead of replacing
            # the existing one
            dom.updateDeviceFlags(xml, get_vm_config_flag(dom, 'all'))
        except Exception as e:
            raise OperationFailed('KCHVMSTOR0009E', {'error': str(e)})

        try:
            if old_disk_used_by is not None and vm_name in old_disk_used_by:
                old_disk_used_by.remove(vm_name)
            if new_disk_used_by is not None:
                new_disk_used_by.append(vm_name)
        except Exception as e:
            wok_log.error('Unable to update dev used_by on update due to'
                          ' %s:' % str(e))
        return dev
示例#18
0
def get_sudoers(admin_check=True):
    """
    method to get user and groups mentioned in /etc/sudoers file
    if admin_check is True - return users and groups with admin privilege
    if False, return users and groups is mentioned in /etc/sudoers file
    :param admin_check: True/False (to check admin/just part of sudoers file)
    :return: list of users and groups
    """
    sudoers = []
    try:
        parser = augeas.Augeas()
        parser.load()
        users = parser.match(SUDOERS_CHECK)
        # sample ouput with augeas:
        # parser.match('etc/sudoers/spec/user')
        # [u'/files/etc/sudoers/spec[1]/user',
        #  u'/files/etc/sudoers/spec[2]/user',
        #  u'/files/etc/sudoers/spec[3]/user']
        # indicates /etc/sudoers file has 3 users/groups
        for user in users:
            name = parser.get(user)
            if isinstance(name, str):
                # augeas returns in unicode format
                name = name.encode('utf-8')
            if admin_check:
                user = user.rstrip('user') + 'host_group'
                # to check for commands and host
                # parser.get('etc/sudoers/spec[1]/host_group/host')
                # u'ALL'
                # parser.get('etc/sudoers/spec[1]/host_group/command')
                # Out[35]: u'ALL'
                if 'ALL' == parser.get(user + '/command') and\
                   'ALL' == parser.get(user + '/host'):
                    sudoers.append(name)
            else:
                sudoers.append(name)
    except Exception as e:
        raise OperationFailed('GINUSER0019E', {'error': e.__str__()})
    return sudoers
示例#19
0
def get_iscsi_session_id(iqn):
    """
    Get the session ID of the given logged in target
    :param iqn: iSCSI Qualified Name
    :return: Session ID of the target
    """
    iscsi_session_id = None
    try:
        current_sessions = os.listdir('/sys/class/iscsi_session')

        for session in current_sessions:
            target_name = open(
                '/sys/class/iscsi_session/' +
                session +
                "/targetname").readline().rstrip()
            if iqn == target_name:
                iscsi_session_id = _parse_session_dir_name(session)
                break
    except Exception as e:
        raise OperationFailed("GINISCSI014E", {'err': e.message, 'iqn': iqn})

    return iscsi_session_id
示例#20
0
文件: utils.py 项目: lcorreia/ginger
def get_discovered_iscsi_qns():
    """
    List the already discovered iSCSI targets on the system
    Returns: Dictionary of discovered IQNs

    """
    discovered_iqns = {}
    iqn_list = []

    try:
        iscsiadm_db_path = '/etc/iscsi/nodes'
        if not os.path.exists(iscsiadm_db_path):
            iscsiadm_db_path = '/var/lib/iscsi/nodes'

        discovered_iqns_list = os.listdir(iscsiadm_db_path)

        for discovered_iqn in discovered_iqns_list:
            discovered_iqns[discovered_iqn] = False

        current_sessions = os.listdir('/sys/class/iscsi_session')

        # Iterate over all sessions once for efficiency instead of
        # calling is_target_logged_in function below for every iqn
        for session in current_sessions:
            target_name = open('/sys/class/iscsi_session/' + session +
                               '/targetname').readline().rstrip()
            discovered_iqns[target_name] = True

        for iqn, status in discovered_iqns.iteritems():
            iqn_list.append({
                'iqn': iqn,
                'status': status,
                'targets': get_iscsi_iqn_auth_info(iqn)
            })

    except Exception as e:
        raise OperationFailed("GINISCSI005E", {'err': e.message})

    return iqn_list
示例#21
0
文件: utils.py 项目: lcorreia/ginger
def iscsiadm_update_db(iqn, db_key, db_key_value):
    """
    Method to update the iscsiadm db
    Args:
        iqn: iSCSI Qualified Name
        db_key: DB Key
        db_key_value: New Value for the DB Key

    Returns: None

    """
    out, err, rc = run_command([
        "iscsiadm", "--m", "node", "--targetname", iqn, "--op=update",
        "--name", db_key, "--value=" + db_key_value
    ])

    if rc != 0:
        raise OperationFailed("GINISCSI011E", {
            'err': err,
            'iqn': iqn,
            'db_key': db_key
        })
示例#22
0
def parse_tape_list(lstape_out):
    """
    Parse the output of the command lstape
    :param lstape_out : Output obtained by 'lstape' command
    """
    try:
        final_list = []
        input_list = lstape_out.splitlines()
        scsi_keys = input_list[0].split()

        for input_device in input_list[1:]:
            device_params = {}
            device_params_list = input_device.split()
            for scsi_key, device_param in zip(scsi_keys, device_params_list):
                device_params[scsi_key] = device_param
            final_list.append(device_params)

    except Exception as e:
        wok_log.error("Unable to parse output of lstape")
        raise OperationFailed("GS390XSTG00016", {'err': e.message})

    return final_list
示例#23
0
文件: rules.py 项目: camovi/ginger
def get_list_of_loaded_control_rules():
    control_rules = []
    control_rules_dict = {
        'backlog_limit': '-b',
        'enabled': '-e',
        'failure': '-f',
        'flag': '-f',
        'rate_limit': '-r'
    }
    cmd_cntl = ['auditctl', '-s']
    out, err, returncode = run_command(cmd_cntl)
    if returncode == 0:
        audit_status = out.split('\n')
        for each_line in audit_status:
            if each_line.split(' ')[0] in control_rules_dict:
                audit_control_rule = control_rules_dict[
                                         each_line.split(' ')[0]] + \
                                     " " + each_line.split(' ')[1]
                control_rules.append(audit_control_rule)
        return control_rules
    else:
        raise OperationFailed('GINAUD0002E', {'name': ' '.join(cmd_cntl)})
示例#24
0
def _get_fs_info(mnt_pt):
    """
    Fetches information about the given filesystem
    :param mnt_pt: mount point of the filesystem
    :return: dictionary containing filesystem info
    """
    fs_info = {}
    try:
        fs_search_list = _get_df_output()
        for i in fs_search_list:
            if mnt_pt == i['mounted_on']:
                fs_info['filesystem'] = i['filesystem']
                fs_info['type'] = i['type']
                fs_info['size'] = i['size']
                fs_info['used'] = i['used']
                fs_info['avail'] = i['avail']
                fs_info['use%'] = i['use%']
                fs_info['mounted_on'] = i['mounted_on']
    except:
        wok_log.error("Fetching fs %s info failed", mnt_pt)
        raise OperationFailed("GINFS00005E", {'device': mnt_pt})
    return fs_info
示例#25
0
    def getPackagesList(self):
        """
        Return a list of package's dictionaries. Each dictionary contains the
        information about a package, in the format
        package = {'package_name': <string>, 'version': <string>,
                   'arch': <string>, 'repository': <string>}
        """
        if self.isRunning():
            raise OperationFailed('GGBPKGUPD0005E')

        gingerBaseLock.acquire()
        self._refreshUpdateList()
        gingerBaseLock.release()
        pkg_list = []
        for pkg in self._pkgs:
            package = {'package_name': pkg.shortname,
                       'version': pkg.candidate.version,
                       'arch': pkg._pkg.architecture,
                       'repository': pkg.candidate.origins[0].label}
            pkg_list.append(package)

        return pkg_list
示例#26
0
 def update(self, name, params):
     if params.get('name') or params.get('ipaddr'):
         raise InvalidParameter("GINSE00009E")
     if not params.get('password'):
         raise MissingParameter("GINSE00008E")
     serverData = get_config(name)
     ipaddr = serverData['ipaddr']
     serverData['salt'] = ''.join(
         random.choice(ALPHABET) for i in range(16))
     serverData['password'] = encrypt(params['password'],
                                      serverData['salt'])
     if params.get('username'):
         serverData['username'] = params['username']
     serverData = get_server_status(serverData)
     if not serverData:
         raise OperationFailed('GINSE00003E', {
             'name': name,
             'ipaddr': ipaddr
         })
     else:
         update_config(serverData)
         return serverData['name']
示例#27
0
    def _set_network_subnet(self, params):
        netaddr = params.get('subnet', '')
        # lookup a free network address for nat and isolated automatically
        if not netaddr:
            netaddr = self._get_available_address()
            if not netaddr:
                raise OperationFailed("KCHNET0009E", {'name': params['name']})

        try:
            ip = ipaddr.IPNetwork(netaddr)
        except ValueError:
            raise InvalidParameter("KCHNET0003E", {'subent': netaddr,
                                                   'network': params['name']})

        if ip.ip == ip.network:
            ip.ip = ip.ip + 1

        dhcp_start = str(ip.ip + ip.numhosts / 2)
        dhcp_end = str(ip.ip + ip.numhosts - 2)
        params.update({'net': str(ip),
                       'dhcp': {'range': {'start': dhcp_start,
                                'end': dhcp_end}}})
示例#28
0
    def getPackageInfo(self, pkg_name):
        """
        Get package information. The return is a dictionary containg the
        information about a package, in the format:

        package = {'package_name': <string>,
                   'version': <string>,
                   'arch': <string>,
                   'repository': <string>
                  }
        """
        self.wait_pkg_manager_available()

        cmd = ["zypper", "info", pkg_name]
        (stdout, stderr, returncode) = run_command(cmd)

        if len(stderr) > 0:
            raise OperationFailed('GGBPKGUPD0006E', {'err': stderr})

        # Zypper returns returncode == 0 and stderr <= 0, even if package is
        # not found in it's base. Need check the output of the command to parse
        # correctly.
        message = '\'%s\' not found' % pkg_name
        if message in stdout:
            raise NotFoundError('GGBPKGUPD0006E', {'err': message})

        package = {}
        stdout = stdout.split('\n')
        for (key, token) in (('repository', 'Repository:'),
                             ('version', 'Version:'),
                             ('arch', 'Arch:'),
                             ('package_name', 'Name:')):
            for line in stdout:
                if line.startswith(token):
                    package[key] = line.split(': ')[1].strip()
                    break

        return package
示例#29
0
    def _create_archive(self, params):
        error = None
        try:
            params['file'] = _tar_create_archive(
                self._archive_dir, params['identity'], params['include'],
                params['exclude'])
            params['checksum'] = {'algorithm': 'sha256',
                                  'value': _sha256sum(params['file'])}

            with self._objstore as session:
                session.store(self._objstore_type, params['identity'], params)
        except TimeoutExpired as e:
            error = e
            reason = 'GINHBK0010E'
        except Exception as e:
            error = e
            reason = 'GINHBK0009E'

        if error is not None:
            msg = 'Error creating archive %s: %s' % (params['identity'], error)
            wok_log.error(msg)

            try:
                with self._objstore as session:
                    session.delete(self._objstore_type, params['identity'],
                                   ignore_missing=True)
            except Exception as e_session:
                wok_log.error('Error cleaning archive meta data %s. '
                              'Error: %s', params['identity'], e_session)

            if params['file'] != '':
                try:
                    os.unlink(params['file'])
                except Exception as e_file:
                    wok_log.error('Error cleaning archive file %s. '
                                  'Error: %s', params['file'], e_file)

            raise OperationFailed(reason, {'identity': params['identity']})
示例#30
0
    def create(self, params):
        if utils.is_lun_scan_enabled()['current']:
            wok_log.error(
                "Lun scan is enabled. Cannot add/remove LUNs manually.")
            raise InvalidOperation("GS390XSTG00009")

        if 'hbaId' not in params:
            wok_log.error("hbaId is required for adding a LUN")
            raise MissingParameter("GS390XSTG00010")

        hbaId = params['hbaId']
        utils.validate_hba_id(hbaId)

        if 'remoteWwpn' not in params:
            wok_log.error("remoteWwpn is required for adding a LUN")
            raise MissingParameter("GS390XSTG00011")

        wwpn = params['remoteWwpn']
        utils.validate_wwpn_or_lun(wwpn)

        if 'lunId' not in params:
            wok_log.error("lunId is required for adding a LUN")
            raise MissingParameter("GS390XSTG00012")

        lunId = params['lunId']
        utils.validate_wwpn_or_lun(lunId)

        try:
            fc_lock.acquire()
            utils.add_lun(hbaId, wwpn, lunId)
        except OperationFailed as e:
            wok_log.error("Adding LUN failed")
            raise OperationFailed("GS390XSTG00003", {'err': e})
        finally:
            fc_lock.release()

        lun_path = hbaId + ":" + wwpn + ":" + lunId
        return lun_path