class ScSshKeysInfo(): def __init__(self, endpoint, token): self.api = ScApi(token, endpoint) def run(self): return {'changed': False, 'ssh_keys': list(self.api.list_ssh_keys())}
class ScCloudComputingInstanceCreate(): def __init__(self, endpoint, token, region_id, name, image_id, image_regexp, flavor_id, flavor_name, gpn_enabled, ipv6_enabled, ssh_key_fingerprint, ssh_key_name, backup_copies, wait, update_interval, checkmode): self.checkmode = checkmode self.api = ScApi(token, endpoint) if region_id is None: raise ModuleError("region_id is mandatory for state=present.") self.region_id = region_id if not name: raise ModuleError("Name is mandatory for state=present.") self.name = name self.instance_id = None self.flavor_id = self.get_flavor_id(flavor_id, flavor_name) self.image_id = self.api.toolbox.find_image_id( image_id=image_id, image_regexp=image_regexp, region_id=region_id, must=True) self.gpn_enabled = gpn_enabled self.ipv6_enabled = ipv6_enabled self.ssh_key_fingerprint = self.get_ssh_key_fingerprint( ssh_key_fingerprint, ssh_key_name) self.backup_copies = backup_copies self.wait = wait self.update_interval = update_interval self.checkmode = checkmode def get_ssh_key_fingerprint(self, ssh_key_fingerprint, ssh_key_name): if ssh_key_fingerprint: return ssh_key_fingerprint if ssh_key_name: for key in self.api.list_ssh_keys(): if key['name'] == ssh_key_name: return key['fingerprint'] raise ModuleError(f"Unable to find ssh key {ssh_key_name}") return None def get_flavor_id(self, flavor_id, flavor_name): if flavor_id and flavor_name: raise ModuleError("Both flavor_id and flavor_name are present.") if not flavor_id and not flavor_name: raise ModuleError('Need either flavor_id or flavor_name.') if flavor_name: flavor_id = self.api.toolbox.find_cloud_flavor_id_by_name( flavor_name=flavor_name, region_id=self.region_id, must=True) return flavor_id def create_instance(self): instance = self.api.post_instance( region_id=self.region_id, name=self.name, flavor_id=self.flavor_id, image_id=self.image_id, gpn_enabled=self.image_id, ipv6_enabled=self.ipv6_enabled, ssh_key_fingerprint=self.ssh_key_fingerprint, backup_copies=self.backup_copies) return instance def wait_for(self, instance): start_time = time.time() instance = self.api.get_instances(instance['id']) if not self.wait: return instance while instance['status'] != 'ACTIVE': time.sleep(self.update_interval) elapsed = time.time() - start_time if elapsed > self.wait: raise WaitError( msg=f"Timeout while waiting instance {instance['id']}" f" to become ACTIVE. Last status was {instance['status']}", timeout=elapsed) instance = self.api.get_instances(instance['id']) return instance def run(self): instance = self.api.toolbox.find_instance(self.instance_id, self.name, self.region_id, must=False) if instance: instance['changed'] = NOT_CHANGED else: if not self.checkmode: instance = self.create_instance() instance = self.wait_for(instance) else: instance = { 'info': 'Instance shold be created, ' 'but check_mode is activated. ' 'no real instance was created.' } instance['changed'] = CHANGED return instance
class ScSshKey(object): def __init__(self, endpoint, token, state, name, fingerprint, public_key, replace, checkmode): self.partial_match = [] self.full_match = [] self.any_match = [] self.api = ScApi(token, endpoint) self.checkmode = checkmode self.replace = replace self.state = state self.key_name = name self.public_key = public_key self.fingerprint = fingerprint if public_key: self.fingerprint = self.extract_fingerprint(public_key) if fingerprint and self.fingerprint != fingerprint: raise ModuleError(msg='Fingerprint does not match public_key') if state == 'absent': if not any([fingerprint, name, public_key]): raise ModuleError( 'Need at least one of name, fingerprint, public_key ' 'for state=absent') if state == 'present': if not public_key: raise ModuleError('Need public_key for state=present') if not name: raise ModuleError('Need name for state=present') @staticmethod def extract_fingerprint(public_key): parts = public_key.split() # real key is the largest word in the line parts.sort(key=len, reverse=True) the_key = base64.decodebytes(parts[0].encode('ascii')) digest = hashlib.md5(the_key).hexdigest() fingerprint = ':'.join(wrap(digest, 2)) return fingerprint @staticmethod def classify_matching_keys(key_list, name, fingerprint): full_match = [] partial_match = [] any_match = [] for key in key_list: if key['name'] == name or key['fingerprint'] == fingerprint: any_match.append(key) if key['name'] == name and key['fingerprint'] == fingerprint: full_match.append(key) else: partial_match.append(key) return (full_match, partial_match, any_match) def add_key(self): if not self.checkmode: return self.api.post_ssh_keys(name=self.key_name, public_key=self.public_key) def delete_keys(self, key_list): if not self.checkmode: for key in key_list: self.api.delete_ssh_keys(fingerprint=key['fingerprint']) def state_absent(self): if not self.any_match: return NOT_CHANGED self.delete_keys(self.any_match) return CHANGED def state_present(self): changed = NOT_CHANGED if self.full_match and not self.partial_match: return NOT_CHANGED if self.partial_match and not self.replace: raise ModuleError( 'Error: Partial match found and no replace option. ' f'Partially matching keys: {repr(self.partial_match)}') if self.partial_match and self.replace: self.delete_keys(self.partial_match) changed = CHANGED if not self.full_match: self.add_key() changed = CHANGED return changed def run(self): self.full_match, self.partial_match, self.any_match = \ self.classify_matching_keys( self.api.list_ssh_keys(), self.key_name, self.fingerprint ) if self.state == 'absent': changed = self.state_absent() if self.state == 'present': changed = self.state_present() return {'changed': changed}