예제 #1
0
파일: users.py 프로젝트: danielhb/ginger
    def delete(self, user):
        adm = libuser.admin()
        user_obj = adm.lookupUserByName(user)
        # Check if user exist
        if user_obj is None:
            kimchi_log.error('User "%s" does not exist', user)
            raise OperationFailed('GINUSER0011E', {'user': user})
        group_obj = adm.lookupGroupById(int(user_obj.get('pw_gid')[0]))
        # Delete user with its home and mails too
        try:
            adm.deleteUser(user_obj, True, True)
        except Exception as e:
            kimchi_log.error('Could not delete user %s: %s', user, e)
            raise OperationFailed('GINUSER0010E', {'user': user})

        # Handle user according to its profile
        self._delete_profile_settings(user)

        # Delete group if no users are assigned to it
        # It is not possible to delete user/group at same time
        if group_obj is None:
            msg = 'Group for user "%s" does not exist for removal' % user
            kimchi_log.warn(msg)
            raise OperationFailed('GINUSER0013E', {'user': user})
        group = group_obj.get('gr_name')[0]
        if not adm.enumerateUsersByGroup(group):
            try:
                adm.deleteGroup(group_obj)
            except Exception as e:
                kimchi_log.error('Could not delete group "%s": %s', group, e)
                raise OperationFailed('GINUSER0012E', {'group': group})
예제 #2
0
파일: auth.py 프로젝트: zofuthan/kimchi
    def authenticate(username, password):
        ldap_server = config.get("authentication", "ldap_server").strip('"')
        ldap_search_base = config.get("authentication",
                                      "ldap_search_base").strip('"')
        ldap_search_filter = config.get("authentication",
                                        "ldap_search_filter",
                                        vars={
                                            "username":
                                            username.encode("utf-8")
                                        }).strip('"')

        connect = ldap.open(ldap_server)
        try:
            result = connect.search_s(ldap_search_base, ldap.SCOPE_SUBTREE,
                                      ldap_search_filter)
            if len(result) == 0:
                entity = ldap_search_filter % {'username': username}
                raise ldap.LDAPError("Invalid ldap entity:%s" % entity)

            connect.bind_s(result[0][0], password)
            connect.unbind_s()
            return True
        except ldap.INVALID_CREDENTIALS:
            # invalid user password
            raise OperationFailed("KCHAUTH0002E")
        except ldap.NO_SUCH_OBJECT:
            # ldap search base specified wrongly.
            raise OperationFailed("KCHAUTH0005E", {
                "item": 'ldap_search_base',
                "value": ldap_search_base
            })
        except ldap.LDAPError, e:
            arg = {"username": username, "code": e.message}
            raise OperationFailed("KCHAUTH0001E", arg)
예제 #3
0
    def update(self, pool, name, params):
        chunk_data = params['chunk'].fullvalue()
        chunk_size = int(params['chunk_size'])

        if len(chunk_data) != chunk_size:
            raise OperationFailed("KCHVOL0026E")

        vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        vol_path = vol.path()
        vol_capacity = vol.info()[1]

        vol_data = upload_volumes.get(vol_path)
        if vol_data is None:
            raise OperationFailed("KCHVOL0027E", {"vol": vol_path})

        cb = vol_data['cb']
        lock = vol_data['lock']
        with lock:
            offset = vol_data['offset']
            if (offset + chunk_size) > vol_capacity:
                raise OperationFailed("KCHVOL0028E")

            cb('%s/%s' % (offset, vol_capacity))
            self.doUpload(cb, vol, offset, chunk_data, chunk_size)
            cb('%s/%s' % (offset + chunk_size, vol_capacity))

            vol_data['offset'] += chunk_size
            if vol_data['offset'] == vol_capacity:
                del upload_volumes[vol_path]
                cb('OK', True)
예제 #4
0
    def create(self, vm_name, params):
        dom = VMModel.get_vm(vm_name, self.conn)
        if DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
            raise InvalidOperation('KCHCDROM0011E')

        # Use device name passed or pick next
        dev_name = params.get('dev', None)
        if dev_name is None:
            params['dev'] = self._get_storage_device_name(vm_name)
        else:
            devices = self.get_list(vm_name)
            if dev_name in devices:
                raise OperationFailed('KCHCDROM0004E', {
                    'dev_name': dev_name,
                    'vm_name': vm_name
                })

        # Path will never be blank due to API.json verification.
        # There is no need to cover this case here.
        path = params['path']
        params['src_type'] = _check_cdrom_path(path)

        # Check if path is an url

        # Add device to VM
        dev_xml = _get_storage_xml(params)
        try:
            conn = self.conn.get()
            dom = conn.lookupByName(vm_name)
            dom.attachDeviceFlags(dev_xml, libvirt.VIR_DOMAIN_AFFECT_CURRENT)
        except Exception as e:
            raise OperationFailed("KCHCDROM0008E", {'error': e.message})
        return params['dev']
예제 #5
0
    def toggleRepo(self, repo_id, enable):
        repos = self._get_repos('KCHREPOS0011E')
        if repo_id not in repos.keys():
            raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id})

        entry = repos.get(repo_id)
        if enable and entry.enabled:
            raise InvalidOperation("KCHREPOS0015E", {'repo_id': repo_id})

        if not enable and not entry.enabled:
            raise InvalidOperation("KCHREPOS0016E", {'repo_id': repo_id})

        kimchiLock.acquire()
        try:
            if enable:
                entry.enable()
            else:
                entry.disable()

            write_repo_to_file(entry)
        except:
            if enable:
                raise OperationFailed("KCHREPOS0020E", {'repo_id': repo_id})

            raise OperationFailed("KCHREPOS0021E", {'repo_id': repo_id})
        finally:
            kimchiLock.release()

        return repo_id
예제 #6
0
    def deactivate(self, name):
        if self._pool_used_by_template(name):
            raise InvalidOperation('KCHPOOL0034E', {'name': name})

        pool = self.get_storagepool(name, self.conn)
        # FIXME: nfs workaround - do not try to deactivate a NFS pool
        # if the NFS server is not reachable.
        xml = pool.XMLDesc(0)
        pool_type = xpath_get_text(xml, "/pool/@type")[0]
        if pool_type == 'netfs' and not self._nfs_status_online(pool):
            # block the user from dactivating the pool.
            source = self._get_storage_source(pool_type, xml)
            raise OperationFailed("KCHPOOL0033E", {
                'name': name,
                'server': source['addr']
            })
            return
        try:
            persistent = pool.isPersistent()
            pool.destroy()
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHPOOL0010E", {
                'name': name,
                'err': e.get_error_message()
            })
        # If pool was not persistent, then it was erased by destroy() and
        # must return nothing here, to trigger _redirect() and avoid errors
        if not persistent:
            return ""
예제 #7
0
 def _update_lvm_disks(self, pool_name, disks):
     # check if all the disks/partitions exists in the host
     for disk in disks:
         lsblk_cmd = ['lsblk', disk]
         output, error, returncode = run_command(lsblk_cmd)
         if returncode != 0:
             kimchi_log.error(
                 '%s is not a valid disk/partition. Could not '
                 'add it to the pool %s.', disk, pool_name)
             raise OperationFailed('KCHPOOL0027E', {
                 'disk': disk,
                 'pool': pool_name
             })
     # add disks to the lvm pool using vgextend + virsh refresh
     vgextend_cmd = ["vgextend", pool_name]
     vgextend_cmd += disks
     output, error, returncode = run_command(vgextend_cmd)
     if returncode != 0:
         msg = "Could not add disks to pool %s, error: %s"
         kimchi_log.error(msg, pool_name, error)
         raise OperationFailed('KCHPOOL0028E', {
             'pool': pool_name,
             'err': error
         })
     # refreshing pool state
     pool = self.get_storagepool(pool_name, self.conn)
     if pool.isActive():
         pool.refresh(0)
예제 #8
0
파일: firmware.py 프로젝트: danielhb/ginger
    def update(self, name, params):
        if detect_live_vm():
            kimchi_log.error('Cannot update system fw while running VMs.')
            raise OperationFailed('GINFW0001E')

        fw_path = params['path']
        pow_ok = params.get('overwrite-perm-ok', True)

        # First unpack the rpm to get the fw img file
        # FIXME: When there's a .deb package available, add support for that
        command = ['rpm', '-U', '--force', '--ignoreos', fw_path]
        output, error, rc = run_command(command)
        if rc:
            # rpm returns num failed pkgs on failure or neg for unknown
            raise OperationFailed('GINFW0002E', {'rc': rc, 'err': error})

        # The image file should now be in /tmp/fwupdate/
        # and match the rpm name.
        image_file, ext = os.path.splitext(os.path.basename(fw_path))
        if image_file is None:
            kimchi_log.error('FW update failed: '
                             'No image file found in the package file.')
            raise OperationFailed('GINFW0003E')
        command = [
            'update_flash', '-f',
            os.path.join('/tmp/fwupdate', '%s.img' % image_file)
        ]
        if not pow_ok:
            command.insert(1, '-n')
        kimchi_log.info('FW update: System will reboot to flash the firmware.')
        output, error, rc = run_command(command)
        if rc:
            raise OperationFailed('GINFW0004E', {'rc': rc})
예제 #9
0
def get_disk_ref_cnt(objstore, conn, path):
    try:
        with objstore as session:
            try:
                ref_cnt = session.get('storagevolume', path)['ref_cnt']
            except NotFoundError:
                kimchi_log.info('Volume %s not found in obj store.' % path)
                ref_cnt = 0
                # try to find this volume in existing vm
                vms_list = VMsModel.get_vms(conn)
                for vm in vms_list:
                    dom = VMModel.get_vm(vm, conn)
                    storages = get_vm_disks(dom)
                    for disk in storages.keys():
                        d_info = get_vm_disk_info(dom, disk)
                        if path == d_info['path']:
                            ref_cnt = ref_cnt + 1
                try:
                    session.store('storagevolume', path, {'ref_cnt': ref_cnt})
                except Exception as e:
                    # Let the exception be raised. If we allow disks'
                    #   ref_cnts to be out of sync, data corruption could
                    #   occour if a disk is added to two guests
                    #   unknowingly.
                    kimchi_log.error(
                        'Unable to store storage volume id in'
                        ' objectstore due error: %s', e.message)
                    raise OperationFailed('KCHVOL0017E', {'err': e.message})
    except Exception as e:
        # This exception is going to catch errors returned by 'with',
        # specially ones generated by 'session.store'. It is outside
        # to avoid conflict with the __exit__ function of 'with'
        raise OperationFailed('KCHVOL0017E', {'err': e.message})
    return ref_cnt
예제 #10
0
def delete_user(username):
    adm = libuser.admin()
    user_obj = adm.lookupUserByName(username)

    if user_obj is None:
        kimchi_log.error('User "%s" does not exist', username)
        raise OperationFailed('GINUSER0011E', {'user': username})
    try:
        adm.deleteUser(user_obj, True, True)
    except Exception as e:
        kimchi_log.error('Could not delete user %s: %s', username, e)
        raise OperationFailed('GINUSER0010E', {'user': username})
예제 #11
0
파일: host.py 프로젝트: shaohef/kimchi
    def swupdate(self, *name):
        try:
            swupdate = SoftwareUpdate()
        except:
            raise OperationFailed('KCHPKGUPD0004E')

        pkgs = swupdate.getNumOfUpdates()
        if pkgs == 0:
            raise OperationFailed('KCHPKGUPD0001E')

        kimchi_log.debug('Host is going to be updated.')
        taskid = add_task('', swupdate.doUpdate, self.objstore, None)
        return self.task.lookup(taskid)
예제 #12
0
 def _ensure_iface_up(self, iface):
     if netinfo.operstate(iface) != 'up':
         _, err, rc = run_command(['ip', 'link', 'set', 'dev', iface, 'up'])
         if rc != 0:
             raise OperationFailed("KCHNET0020E",
                                   {'iface': iface, 'err': err})
         # Add a delay to wait for the link change takes into effect.
         for i in range(10):
             time.sleep(1)
             if netinfo.operstate(iface) == 'up':
                 break
         else:
             raise OperationFailed("KCHNET0021E", {'iface': iface})
예제 #13
0
def parse_request():
    if 'Content-Length' not in cherrypy.request.headers:
        return {}
    rawbody = cherrypy.request.body.read()

    if mime_in_header('Content-Type', 'application/json'):
        try:
            return json.loads(rawbody)
        except ValueError:
            e = OperationFailed('KCHAPI0006E')
            raise cherrypy.HTTPError(400, e.message)
    else:
        e = OperationFailed('KCHAPI0007E')
        raise cherrypy.HTTPError(415, e.message)
예제 #14
0
 def connect(self, name):
     graphics = self._vm_get_graphics(name)
     graphics_type, graphics_listen, graphics_port = graphics
     if graphics_port is not None:
         vnc.add_proxy_token(name, graphics_port)
     else:
         raise OperationFailed("KCHVM0010E", {'name': name})
예제 #15
0
    def delete(self, name):
        conn = self.conn.get()
        dom = self.get_vm(name, self.conn)
        self._vmscreenshot_delete(dom.UUIDString())
        paths = self._vm_get_disk_paths(dom)
        info = self.lookup(name)

        if info['state'] == 'running':
            self.poweroff(name)

        try:
            dom.undefine()
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVM0021E", {
                'name': name,
                'err': e.get_error_message()
            })

        for path in paths:
            vol = conn.storageVolLookupByPath(path)
            pool = vol.storagePoolLookupByVolume()
            xml = pool.XMLDesc(0)
            pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
            if pool_type not in READONLY_POOL_TYPE:
                vol.delete(0)
        try:
            with self.objstore as session:
                session.delete('vm', dom.UUIDString(), ignore_missing=True)
        except Exception as e:
            # It is possible to delete vm without delete its database info
            kimchi_log.error(
                'Error deleting vm information from database: '
                '%s', e.message)

        vnc.remove_proxy_token(name)
예제 #16
0
    def _static_vm_update(self, dom, params):
        state = DOM_STATE_MAP[dom.info()[0]]
        old_xml = new_xml = dom.XMLDesc(0)

        for key, val in params.items():
            if key in VM_STATIC_UPDATE_PARAMS:
                if key == 'memory':
                    # Libvirt saves memory in KiB. Retrieved xml has memory
                    # in KiB too, so new valeu must be in KiB here
                    val = val * 1024
                if type(val) == int:
                    val = str(val)
                xpath = VM_STATIC_UPDATE_PARAMS[key]
                new_xml = xmlutils.xml_item_update(new_xml, xpath, val)

        conn = self.conn.get()
        try:
            if 'name' in params:
                if state == 'running':
                    msg_args = {'name': dom.name(), 'new_name': params['name']}
                    raise InvalidParameter("KCHVM0003E", msg_args)

                # Undefine old vm, only if name is going to change
                dom.undefine()

            root = ET.fromstring(new_xml)
            root.remove(root.find('.currentMemory'))
            dom = conn.defineXML(ET.tostring(root, encoding="utf-8"))
        except libvirt.libvirtError as e:
            dom = conn.defineXML(old_xml)
            raise OperationFailed("KCHVM0008E", {
                'name': dom.name(),
                'err': e.get_error_message()
            })
        return dom
예제 #17
0
    def create(self, params):
        conn = self.conn.get()
        name = params['name']
        if name in self.get_list():
            raise InvalidOperation("KCHNET0001E", {'name': name})

        connection = params["connection"]
        # set forward mode, isolated do not need forward
        if connection != 'isolated':
            params['forward'] = {'mode': connection}

        # set subnet, bridge network do not need subnet
        if connection in ["nat", 'isolated']:
            self._set_network_subnet(params)

        # only bridge network need bridge(linux bridge) or interface(macvtap)
        if connection == 'bridge':
            self._set_network_bridge(params)

        params['name'] = escape(params['name'])
        xml = to_network_xml(**params)

        try:
            network = conn.networkDefineXML(xml.encode("utf-8"))
            network.setAutostart(True)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHNET0008E", {
                'name': name,
                'err': e.get_error_message()
            })

        return name
예제 #18
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
                }
            }
        })
예제 #19
0
    def addRepo(self, params):
        """
        Add a new APT repository based on <params>
        """
        # To create a APT repository the dist is a required parameter
        # (in addition to baseurl, verified on controller through API.json)
        config = params.get('config', None)
        if config is None:
            raise MissingParameter("KCHREPOS0019E")

        if 'dist' not in config.keys():
            raise MissingParameter("KCHREPOS0019E")

        uri = params['baseurl']
        dist = config['dist']
        comps = config.get('comps', [])

        validate_repo_url(uri)

        kimchiLock.acquire()
        try:
            repos = self._get_repos()
            source_entry = repos.add('deb',
                                     uri,
                                     dist,
                                     comps,
                                     file=self.filename)
            with self.pkg_lock():
                repos.save()
        except Exception as e:
            kimchiLock.release()
            raise OperationFailed("KCHREPOS0026E", {'err': e.message})
        kimchiLock.release()
        return self._get_repo_id(source_entry)
예제 #20
0
 def _get_repos(self, errcode):
     try:
         kimchiLock.acquire()
         repos = get_yum_repositories()
     except Exception, e:
         kimchiLock.release()
         raise OperationFailed(errcode, {'err': str(e)})
예제 #21
0
    def addRepo(self, params):
        """
        Add a given repository to YumBase
        """
        # At least one base url, or one mirror, must be given.
        baseurl = params.get('baseurl', '')

        config = params.get('config', {})
        mirrorlist = config.get('mirrorlist', '')
        metalink = config.get('metalink', '')
        if not baseurl and not mirrorlist and not metalink:
            raise MissingParameter("KCHREPOS0013E")

        if baseurl:
            validate_repo_url(baseurl)

        if mirrorlist:
            validate_repo_url(mirrorlist)

        if metalink:
            validate_repo_url(metalink)

        if mirrorlist and metalink:
            raise InvalidOperation('KCHREPOS0030E')

        repo_id = params.get('repo_id', None)
        if repo_id is None:
            repo_id = "kimchi_repo_%s" % str(int(time.time() * 1000))

        repos = self._get_repos('KCHREPOS0026E')
        if repo_id in repos.keys():
            raise InvalidOperation("KCHREPOS0022E", {'repo_id': repo_id})

        repo_name = config.get('repo_name', repo_id)
        repo = {
            'baseurl': baseurl,
            'mirrorlist': mirrorlist,
            'name': repo_name,
            'gpgcheck': 1,
            'gpgkey': [],
            'enabled': 1,
            'metalink': metalink
        }

        # write a repo file in the system with repo{} information.
        parser = ConfigParser()
        parser.add_section(repo_id)

        for key, value in repo.iteritems():
            if value:
                parser.set(repo_id, key, value)

        repofile = os.path.join(self._confdir, repo_id + '.repo')
        try:
            with open(repofile, 'w') as fd:
                parser.write(fd)
        except:
            raise OperationFailed("KCHREPOS0018E", {'repo_file': repofile})

        return repo_id
예제 #22
0
파일: network.py 프로젝트: danielhb/ginger
    def _set_default_gateway(self, gateway):
        old_route = self._get_default_route_entry()
        if old_route is None:
            old_gateway, old_iface = None, None
        else:
            old_gateway, old_iface = old_route.gateway, old_route.dev

        _, err, rc = run_command(['ip', 'route', 'del', 'default'])
        if rc and not ('No such process' in err):
            raise OperationFailed('GINNET0010E', {'reason': err})
        _, err, rc = run_command(
            ['ip', 'route', 'add', 'default', 'via', gateway])
        if rc:
            raise OperationFailed('GINNET0011E', {'reason': err})

        self._save_gateway_changes(old_iface, old_gateway)
예제 #23
0
    def _gen_debugreport_file(self, name):
        gen_cmd = self.get_system_report_tool()

        if gen_cmd is not None:
            return add_task('', gen_cmd, self.objstore, name)

        raise OperationFailed("KCHDR0002E")
예제 #24
0
 def reset(self, name):
     dom = self.get_vm(name, self.conn)
     try:
         dom.reset(flags=0)
     except libvirt.libvirtError as e:
         raise OperationFailed("KCHVM0022E",
                               {'name': name, 'err': e.get_error_message()})
예제 #25
0
파일: auth.py 프로젝트: zofuthan/kimchi
        def _auth(result):
            def _pam_conv(auth, query_list, userData=None):
                resp = []
                for i in range(len(query_list)):
                    query, qtype = query_list[i]
                    if qtype == PAM.PAM_PROMPT_ECHO_ON:
                        resp.append((username, 0))
                    elif qtype == PAM.PAM_PROMPT_ECHO_OFF:
                        resp.append((password, 0))
                    elif qtype == PAM.PAM_PROMPT_ERROR_MSG:
                        cherrypy.log.error_log.error(
                            "PAM authenticate prompt error: %s" % query)
                        resp.append(('', 0))
                    elif qtype == PAM.PAM_PROMPT_TEXT_INFO:
                        resp.append(('', 0))
                    else:
                        return None
                return resp

            result.value = False
            auth = PAM.pam()
            auth.start(service)
            auth.set_item(PAM.PAM_USER, username)
            auth.set_item(PAM.PAM_CONV, _pam_conv)
            try:
                auth.authenticate()
            except PAM.error, (resp, code):
                msg_args = {'username': username, 'code': code}
                raise OperationFailed("KCHAUTH0001E", msg_args)
예제 #26
0
파일: firmware.py 프로젝트: danielhb/ginger
 def reject(self, name):
     command = ['update_flash', '-r']
     output, error, rc = run_command(command)
     if rc:
         raise OperationFailed('GINFW0006E', {'rc': rc})
     # update_flash returns a message on success, so log it.
     kimchi_log.info(output)
예제 #27
0
 def connect(self, name):
     # (type, listen, port, passwd, passwdValidTo)
     graphics_port = self._vm_get_graphics(name)[2]
     if graphics_port is not None:
         vnc.add_proxy_token(name, graphics_port)
     else:
         raise OperationFailed("KCHVM0010E", {'name': name})
예제 #28
0
    def lookup(self, name):
        try:
            swupdate = SoftwareUpdate()
        except Exception:
            raise OperationFailed('KCHPKGUPD0004E')

        return swupdate.getUpdate(name)
예제 #29
0
    def __init__(self, args, scan=False):
        """
        Construct a VM Template from a widely variable amount of information.
        The only required parameter is a name for the VMTemplate.  If present,
        the os_distro and os_version fields are used to lookup recommended
        settings.  Any parameters provided by the caller will override the
        defaults.  If scan is True and a cdrom or a base img is present, the
        operating system will be detected by probing the installation media.
        """
        self.info = {}
        self.fc_host_support = args.get('fc_host_support')

        # Fetch defaults based on the os distro and version
        try:
            distro, version = self._get_os_info(args, scan)
        except ImageFormatError as e:
            raise OperationFailed('KCHTMPL0020E', {'err': e.message})
        os_distro = args.get('os_distro', distro)
        os_version = args.get('os_version', version)
        entry = osinfo.lookup(os_distro, os_version)
        self.info.update(entry)

        # Auto-generate a template name and no one is passed
        if 'name' not in args or args['name'] == '':
            args['name'] = self._gen_name(distro, version)
        self.name = args['name']

        # Override with the passed in parameters
        graph_args = args.get('graphics')
        if graph_args:
            graphics = dict(self.info['graphics'])
            graphics.update(graph_args)
            args['graphics'] = graphics
        self.info.update(args)
예제 #30
0
파일: network.py 프로젝트: danielhb/ginger
 def _set_nameservers(self, nameservers):
     try:
         with open(RESOLV_CONF, 'w') as f:
             f.write(''.join('nameserver %s\n' % server
                             for server in nameservers))
     except IOError as e:
         raise OperationFailed('GINNET0002E', {'reason': e.message})