def create(self, lv_name, lv_size): """Create logical volume; return True""" lv_size = str(lv_size) + self.lv_units lv_name = common.validate_hostname( lv_name) # LV names are always hostnames lv_size = common.validate_storage_format(lv_size) args = ['lvcreate', '-n', lv_name, '-L', lv_size, self.vg_name] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args # trace = traceback.format_exec() raise error.SpokeError(msg) data = result.communicate() stdout = data[0] stderr = data[1] msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) # Errors we know about if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "Insufficient free extents" in stderr: msg = "Not enough free space to create LV" raise error.InsufficientResource(msg) elif "Logical volume \"%s\" already exists in volume group \"%s\"" % ( lv_name, self.vg_name) in stderr: msg = "Logical volume '%s' already exists in volume group '%s'" % ( lv_name, self.vg_name) raise error.AlreadyExists(msg) # Catch unexpected errors if result.returncode != 0: msg = "Create command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) result = self.get(lv_name) if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Created %s:" % result['type'] return result else: msg = 'Create operation returned OK, but unable to find object' raise error.NotFound(msg) self.log.debug('Result: %s' % result) return result
def _delete_object(self, dn, dn_info=None): """Delete an LDAP object (e.g. a dn or attribute).""" operation = { 'del_dn': self.LDAP.delete_s, 'del_attr': self.LDAP.modify_s } filter = 'objectClass=*' if dn_info == None: del_type = 'del_dn' # We're deleting a dn kargs = {'dn': dn} attrlist = None else: del_type = 'del_attr' # We're deleting an attribute kargs = {'dn': dn, 'modlist': dn_info} attrlist = [] # Collect a list of attributes to return for item in dn_info: attrlist.append(item[1]) #if len(dn_info) == 1: # Try and construct a filter # filter = '%s=%s' % (dn_info[0][1], dn_info[0][2]) #self.log.debug('Running with filter %s' % filter) try: operation[del_type](**kargs) except ldap.NO_SUCH_OBJECT, e: msg = '%s does not exist, cannot delete' % dn raise error.NotFound(msg)
def delete(self): """Delete a CA's file structure and configuration files.""" # NB This will fail if you've been storing certs or reqs if self.get()['data'] == []: msg = '%s does not exist, cannot delete' % self.ca_name raise error.NotFound(msg) self.req_files.append(self.ca_req_file) for req_file in self.req_files: if (os.path.exists(req_file)): os.remove(req_file) self.req_dirs.sort(reverse=True) for directory in self.req_dirs: if (os.path.exists(directory)): try: os.removedirs(directory) except Exception as e: msg = 'Unable to delete directory %s: %s' % (directory, e) self.log.debug(msg) result = self.get() if result['exit_code'] == 3 and result['count'] == 0: result['msg'] = "Deleted %s:" % result['type'] return result else: msg = 'Delete operation returned OK, but object still there?' raise error.ValidationError(msg)
def create(self, aloc_ips=None): """Create subnet kv stores; populate with IPs; return True.""" if not (self.network and self.mask): msg = 'Please specify ip and mask' raise error.InputError(msg) if self.KV.exists(self.kv_aloc) or self.KV.exists(self.kv_free): msg = 'Subnet %s/%s already exists' % (self.kv_name, str( self.mask)) raise error.AlreadyExists(msg) self._populate_aloc_ips(aloc_ips) self._populate_free_ips() msg = 'Created subnet %s/%s with %s free and %s reserved IPs' \ % (self.kv_name, str(self.mask), len(self.free_ips), len(self.aloc_ips)) self.log.debug(msg) result = self.get() if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Created %s:" % result['type'] return result else: msg = 'Create operation returned OK, but unable to find object' raise error.NotFound(msg) return result
def create(self): """Create a DNS zone; return a DNS zone object.""" filter = '(%s:dn:=%s)' % (self.dns_zone_name_attr, self.domain_name) dn = self.zone_dn dn_attr = { 'objectClass': ['top', self.dns_zone_class], 'relativeDomainName': ['@'], 'zoneName': [self.domain_name] } dn_info = [(k, v) for (k, v) in dn_attr.items()] self.log.debug('Adding DNS zone: ' + dn) try: result = self._create_object(dn, dn_info) except error.NotFound: # Let's see if it's just the dns container missing. child_dn = '%s=%s,%s' % (self.dns_cont_attr, self.dns_cont_name, \ self.org_dn) child_dn_attr = { 'objectClass': ['top', self.dns_cont_class], self.dns_cont_attr: [self.dns_cont_name] } child_dn_info = [(k, v) for (k, v) in child_dn_attr.items()] try: self._create_object(child_dn, child_dn_info) except error.NotFound: # Not it wasn't just the dns container msg = "Part of %s missing, can't create." % dn raise error.NotFound(msg) # And then try the original create zone again. result = self._create_object(dn, dn_info) self.log.debug('Result: %s' % result) return result
def _create_object(self, dn, dn_info): """Create a new LDAP object (e.g. a dn or attribute).""" # Allowed LDAP operations operation = {'add':self.LDAP.add_s, 'mod':self.LDAP.modify_s} try: int(dn_info[0][0]) #attribute mod opertations begin with an integer. type = 'mod' attrlist = [] # Collect a list of attributes to return for item in dn_info: attrlist.append(item[1]) except: type = 'add' #if it's not a modification, it's an add operation. attrlist = None try: operation[type](dn, dn_info) except ldap.ALREADY_EXISTS: msg = 'Entry %s already exists.' % dn raise error.AlreadyExists(msg) except ldap.TYPE_OR_VALUE_EXISTS: msg = 'Attempt to add attribute to %s which already exists.' % dn raise error.AlreadyExists(msg) except ldap.CONSTRAINT_VIOLATION: msg = 'Attribute already exists and does not support multiples' raise error.AlreadyExists(msg) except ldap.NO_SUCH_OBJECT: msg = "Part of %s missing, can't create." % dn raise error.NotFound(msg) except ldap.LDAPError, e: trace = traceback.format_exc() raise error.SpokeLDAPError(e, trace)
def modify(self, vm_power_state): '''Change the power state of a vm''' if vm_power_state == "on": result = self.create() elif vm_power_state == "off": result = self.delete() elif vm_power_state == "reboot": try: result = self.dom.reboot(0) msg = "Power cycled %s" % self.vm_name self.log.debug(msg) except libvirt.libvirtError: msg = "Failed to power cycle %s" % self.vm_name raise error.LibvirtError(msg) if result != 0: msg = 'Unknown error rebooting VM, libvirt returned %s' % result raise error.LibvirtError(msg) elif vm_power_state == "forceoff": result = self.delete(force=True) else: msg = "Invalid state, must be one of: on|off|reboot|forceoff" raise error.InputError, msg #self.conn.close() result = self.get() if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Modified %s:" % result['type'] return result else: msg = 'Power operation returned OK, but unable to find object' raise error.NotFound(msg) return result
def __init__(self, hv_uri, vm_name): '''Get some basic config and connect to hypervisor''' SpokeVMPower.__init__(self, vm_name) self.hv_uri = hv_uri self.vm_name = common.validate_hostname(vm_name) self.conn = None try: self.conn = libvirt.open(self.hv_uri) msg = "Successfully connected to: " + self.hv_uri self.log.debug(msg) except libvirt.libvirtError: trace = traceback.format_exc() msg = 'Libvirt connection to URI %s failed' % self.hv_uri raise error.LibvirtError(msg, trace) except Exception: trace = traceback.format_exc() msg = 'Unknown error' raise error.SpokeError(msg, trace) finally: if self.conn == None: msg = 'Libvirt connection to URI %s failed' % self.hv_uri raise error.LibvirtError(msg) try: self.dom = self.conn.lookupByName(self.vm_name) except libvirt.libvirtError: msg = "VM %s not found." % self.vm_name raise error.NotFound(msg)
def create(self, repo): """Enable user access to a repository; return repository info.""" repo = self._validate_input(repo) filter = '%s=%s' % (self.svn_repo_attr, repo) scope = self.search_scope dn = self.user_dn dn_info = [] try: if repo in self.user_attrs[self.svn_repo_attr]: msg = 'Repository %s already enabled for user %s.' % \ (repo, self.user_dn) raise error.AlreadyExists(msg) else: msg = 'Repository %s not found, creating...' % repo raise error.NotFound(msg) except (KeyError, error.NotFound): if not self.svn_class in self.user_classes: # This is our first repository, so add class and enable. dn_info.append((0, 'objectClass', self.svn_class)) dn_info.append((0, self.svn_enable_attr, 'TRUE')) dn_info.append((0, self.svn_repo_attr, repo)) self.log.debug('Adding %s to %s ' % (dn_info, dn)) result = self._create_object(dn, dn_info) self.log.debug('Result: %s' % result) return result
def _get_ca(self, ca_name): ca_name = common.is_shell_safe(ca_name) ca = SpokeCA(ca_name) if not ca.get()['data']: msg = "Can't find CA %s" % ca_name raise error.NotFound(msg) return ca
def modify(self, org_name, suffix): """Modify an org's default suffix; return True.""" org_info = self.get(org_name)['data'] if org_info == []: msg = 'Unable to modify org suffix, no org found.' self.log.error(msg) raise error.NotFound(msg) dn = org_info[0].__getitem__(0) old_result = org_info[0].__getitem__(1) old_classes = old_result['objectClass'] try: old_attrs = {self.org_suffix_attr:old_result[self.org_suffix_attr]} except KeyError: # suffix has not been set. old_attrs = {self.org_suffix_attr: ''} #new_attrs = {'objectClass': [self.user_class] } #self.org_suffix_attr: suffix} new_attrs = {self.org_suffix_attr: suffix} if not self.user_class in old_classes: new_attrs['objectClass'] = self.user_class if new_attrs == old_attrs: msg = 'New suffix is equal to old suffix, nothing to update.' self.log.debug(msg) return True self._modify_attributes(dn, new_attrs, old_attrs)
def _get_dhcp_group(self, dhcp_server, group_name): """Retrieve a DHCP group object.""" group = SpokeDHCPGroup(dhcp_server) result = group.get(group_name) if result['data'] == []: msg = "Can't find DHCP group for %s" % dhcp_server raise error.NotFound(msg) return result
def _get_user(self, org_name, user_id): """Retrieve a user object.""" user = SpokeUser(org_name) result = user.get(user_id, unique=True) if result['data'] == []: msg = "Can't find user %s in org %s" % (user_id, org_name) raise error.NotFound(msg) return result
def _get_org(self, org_name): """Retrieve our org object.""" org = SpokeOrg() result = org.get(org_name) if result['data'] == []: msg = "Can't find org %s" % org_name raise error.NotFound(msg) return result
def _get_list(self, org_name, list_address): list = SpokeMailingList(org_name) result = list.get(list_address) if result['data'] == []: msg = "Can't find mailing list %s in %s" % (list_address, org_name) self.log.error(msg) raise error.NotFound(msg) return result
def delete(self, lv_name): """Delete logical volume; return True.""" lv_name = common.validate_hostname( lv_name) # LV names are always hostnames args = ['lvremove', '-f', '%s/%s' % (self.vg_name, lv_name)] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args #trace = traceback.format_exec() raise error.SpokeError(msg) data = result.communicate() stdout = data[0] stderr = data[1] msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "logical volume(s) not found" in stderr: msg = "logical volume '%s' not found." % lv_name raise error.NotFound(msg) # Catch non-specific errors if result.returncode != 0: msg = "Delete command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) result = self.get(lv_name) if result['exit_code'] == 3 and result['count'] == 0: result['msg'] = "Deleted %s:" % result['type'] self.log.debug('Result: %s' % result) return result else: msg = 'Delete operation returned OK, but object still there?' raise error.SearchError(msg)
def _get_dhcp_service(self, dhcp_server): """Retrieve a DHCP service object.""" service = SpokeDHCPService() result = service.get(dhcp_server) if result['data'] == []: msg = "Can't find DHCP service for %s" % dhcp_server raise error.NotFound(msg) return result
def _verify(self): """Verify a certificate request; return True (0) or False (1)""" try: req = X509.load_request(self.req_file) except: msg = 'Certificate request file %s not found' % self.req_file raise error.NotFound(msg) pkey = req.get_pubkey() return req.verify(pkey)
def _get_dhcp_host(self, dhcp_server, group_name, host_name): """Retrieve a DHCP host object.""" host = SpokeDHCPHost(dhcp_server, group_name) result = host.get(host_name) if result['data'] == []: msg = "Can't find DHCP host for %s in group %s" % (dhcp_server, \ group_name) raise error.NotFound(msg) return result
def _modify_attributes(self, dn, new_attrs, old_attrs=None): """Modify an LDAP object (e.g. a dn or attribute).""" ignore_old = 0 if old_attrs==None: old_object = self._get_object(dn, ldap.SCOPE_BASE, '(objectClass=*)', unique=True) if old_object['data'] == []: msg = '%s does not exist, cannot modify' % dn raise error.NotFound(msg) old_attrs = old_object['data'][0][1] ignore_old = 1 dn_info = ldap.modlist.modifyModlist(old_attrs, new_attrs, ignore_oldexistent=ignore_old) try: self.LDAP.modify_s(dn, dn_info) except ldap.NO_SUCH_ATTRIBUTE, e: msg = 'Attribute does not exist, cannot modify' raise error.NotFound(msg)
def delete(self): """Delete a user account's password; return True.""" dn_info = [] dn = self.user_dn if not self.user_pwd_attr in self.user_attrs: msg = 'Password missing for user %s, cannot delete.' % self.user_id raise error.NotFound(msg) dn_info.append((ldap.MOD_DELETE, self.user_pwd_attr, None)) self.log.debug('Deleting %s from user %s ' % (dn_info, dn)) result = self._delete_object(dn, dn_info) result['msg'] = 'Password deleted for user %s' % self.user_id self.log.debug('Result: %s' % result) return result
def delete(self): """Delete a certificate and its associated key.""" # NB This will fail if you've been storing certs or reqs for file in (self.key_file, self.cert_file): try: os.remove(file) except (OSError, IOError): msg = 'Unable to delete file %s' % file raise error.NotFound(msg) result = self.get() if result['exit_code'] == 3 and result['count'] == 0: result['msg'] = "Deleted %s:" % result['type'] return result else: msg = 'Delete operation returned OK, but object still there?' raise error.ValidationError(msg)
def create(self): '''Power on a VM''' try: self.dom.create() except libvirt.libvirtError: msg = "VM %s is already powered on." % self.vm_name raise error.VMRunning, msg #self.conn.close() result = self.get() if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Powered on %s:" % result['type'] return result else: msg = 'Power operation returned OK, but unable to find object' raise error.NotFound(msg) return result
def create(self): """Create certificate request; return certificate request file.""" try: pkey = self._gen_and_save_key(self.key_file) except IOError: msg = 'Failed to open key file: ' + self.key_file raise error.NotFound(msg) name = self._gen_x509_name(self.cn) req = X509.Request() req.set_version(3) req.set_pubkey(pkey) req.set_subject_name(name) req.sign(pkey, 'sha1') req.save(self.req_file) result = self.get() return result
def __init__(self, org_name): """Get config, setup logging and LDAP connection.""" SpokeLDAP.__init__(self) self.config = config.setup() self.log = logging.getLogger(__name__) self.search_scope = 2 # ldap.SCOPE_SUBTREE self.retrieve_attr = None self.base_dn = self.config.get('LDAP', 'basedn') self.org_name = org_name self.org = self._get_org(self.org_name) if self.org['data'] == []: msg = 'Org %s not found: cannot delete children' % self.org_name raise error.NotFound(msg) self.org_dn = self.org['data'][0].__getitem__(0) self.container_attr = self.config.get('ATTR_MAP', 'container_attr', 'ou') self.container_class = self.config.get('ATTR_MAP', \ 'container_class', 'organizationalUnit')
def delete(self): """Delete UUID object; return True.""" dn = self.next_uuid_dn dn_info = [] if self.next_uuid_class in self.next_uuid_classes: dn_info.append((1, 'objectClass', self.next_uuid_class)) if self.next_uuid_attr in self.next_uuid_attrs: dn_info.append((1, self.next_uuid_attr, None)) if dn_info == []: msg = 'No UUID found, nothing to delete.' raise error.NotFound(msg) self.log.debug('Deleting %s from %s ' % (dn_info, dn)) result = self._delete_object(dn, dn_info) result['msg'] = 'Deleted UUID:' self.log.debug('Result: %s' % result) return result
def create(self, mac, template, run_id=None): """Creates a config at mac using template""" mac = common.validate_mac(mac) if run_id is not None: if not common.is_integer(run_id): msg = "Run ID must be an integer or not defined" raise error.InputError, msg mac = string.replace(mac, ":", "-") #Format for use on tftp filesystem template = self._validate_template(template) template_path = self.tftp_dir + template template_file = open(template_path) dst = self.tftp_dir + self.tftp_prefix + mac #Check that at least one line has kernel arguments kernel_arg_lines = 0 for line in template_file: if 'append' in line: kernel_arg_lines += 1 if kernel_arg_lines < 1 and run_id is not None: msg = "No kernel arguments in specified template. Should be more than one line starting append." raise error.InputError, msg template_file.close template_file = open(template_path) #Check that nothing exists at that mac location before trying to make a file if not os.path.lexists(dst): mac_file = open(dst, 'w') #Loop file adding run_id at correct line for line in template_file: if 'append' in line and run_id: #remove the line break and add run_id at end of kernel args line = line.rstrip('\n') mac_file.write(line + " run_id=" + str(run_id) + "\n") else: mac_file.write(line) mac_file.close else: msg = "Config for mac %s already exists, can't create" % mac raise error.AlreadyExists, msg result = self.search(mac) if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Created %s:" % result['type'] return result else: msg = 'Create operation returned OK, but unable to find object' raise error.NotFound(msg) return result
def delete(self, delete_key=True): """Delete a certificate request; return True""" try: os.remove(self.req_file) if delete_key: os.remove(self.key_file) except (OSError, IOError): msg = 'Failed to delete request %s and/or key %s' \ % (self.req_file, self.key_file) raise error.NotFound(msg) except Exception as e: raise e result = self.get() if result['exit_code'] == 3 and result['count'] == 0: result['msg'] = "Deleted %s:" % result['type'] return result else: msg = 'Delete operation returned OK, but object still there?' raise error.ValidationError(msg)
def delete(self, repo): """Disable user access to a repository; return True.""" repo = self._validate_input(repo) filter = '%s=%s' % (self.svn_repo_attr, repo) dn = self.user_dn dn_info = [] if self.svn_repo_attr in self.user_attrs: dn_info.append((1, self.svn_repo_attr, repo)) if len(self.user_attrs) == 1: # This is the last repository, so we can delete the class also. dn_info.append((1, 'objectClass', self.svn_class)) if dn_info == []: msg = 'Repository not enabled for user %s.' % self.user_dn raise error.NotFound(msg) self.log.debug('Deleting %s from %s ' % (dn_info, dn)) result = self._delete_object(dn, dn_info) self.log.debug('Result: %s' % result) return result
def modify(self, list_address, enable): """Enable/Disable a mailing list; return True.""" list_address = self._validate_input(list_address) list_info = self.get(list_address) if list_info['data'] == []: msg = 'Unable to modify mailing list access, no list found.' raise error.NotFound(msg) dn = list_info['data'][0].__getitem__(0) old_result = list_info['data'][0].__getitem__(1) old_attrs = {self.list_enable_attr: old_result[self.list_enable_attr]} if enable == True: new_attrs = {self.list_enable_attr: 'TRUE'} elif enable == False: new_attrs = {self.list_enable_attr: 'FALSE'} else: msg = 'enable can only be one of True or False' raise error.InputError(msg) result = self._modify_attributes(dn, new_attrs, old_attrs) self.log.debug('Result: %s' % result) return result