class OkeanosConnector(AbstractConnector): """ Okeanos connector. """ def __init__(self): AbstractConnector.__init__(self) self.__cyclades = None self.__network_client = None self.attach_public_ipv4 = False self.private_network = -1 def authenticate(self, authentication=None): """ :param authentication: :return: """ if self.__cyclades is not None: return True try: authcl = AstakosClient(authentication['URL'], authentication['TOKEN']) authcl.authenticate() self.__cyclades = CycladesClient( authcl.get_service_endpoints('compute')['publicURL'], authentication['TOKEN']) self.__network_client = CycladesNetworkClient( authcl.get_service_endpoints('network')['publicURL'], authentication['TOKEN']) except ClientError: stderr.write('Connector initialization failed') return False return True def configure(self, configuration): self.authenticate(configuration['auth']) if 'private_network' in configuration and configuration[ 'private_network']: self.private_network = 0 if 'attach_public_ipv4' in configuration and configuration[ 'attach_public_ipv4']: self.attach_public_ipv4 = True def prepare(self): """ In this method, application-level IaaS related actions are executed. :return: """ if self.private_network == 0: self.private_network = self.create_private_network() def create_vm(self, name, flavor_id, image_id): """ :param name: :param flavor_id: :param image_id: :return: """ networks = [] if self.attach_public_ipv4: networks.append({'uuid': self.__create_floating_ip()}) if self.private_network != -1: networks.append({'uuid': self.private_network}) response = self.__cyclades.create_server(name=name, flavor_id=flavor_id, image_id=image_id, networks=networks) ret_value = dict() ret_value['password'] = response['adminPass'] ret_value['id'] = response['id'] ret_value['user'] = response['metadata']['users'] ret_value['hostname'] = 'snf-' + str( response['id']) + '.vm.okeanos.grnet.gr' self.__cyclades.wait_server(server_id=ret_value['id'], current_status='ACTIVE') return ret_value def delete_vm(self, server_id): """ Delete VM method. The method is blocking until the VM goes to a "DELETED" state :param server_id: :return: """ attachments = self.__cyclades.get_server_details( server_id)['attachments'] port_id = None for a in attachments: if a['OS-EXT-IPS:type'] == 'floating': port_id = a['id'] floating_ip_id = None for ip in self.__network_client.list_floatingips(): if port_id is not None and ip['port_id'] == str(port_id): floating_ip_id = ip['id'] self.__cyclades.delete_server(server_id) self.__cyclades.wait_server( server_id, current_status='DELETED') # wait until server is deleted if floating_ip_id is not None: self.__wait_until_ip_released(floating_ip_id) self.__network_client.delete_floatingip(floating_ip_id) def __wait_until_ip_released(self, floating_ip_id): for i in range(1, MAX_WAIT_FOR_LOOPS + 1): for ip in self.__network_client.list_floatingips(): if ip['id'] == floating_ip_id: if ip['instance_id'] is None or ip['instance_id'] == 'None': return True sleep(SLEEP_TIMEOUT) def list_vms(self): """ :return: """ return self.__cyclades.list_servers() def get_status(self, vm_id): """ :param vm_id: :return: """ return self.__cyclades.get_server_details(vm_id) def get_server_addresses(self, vm_id, ip_version=None, connection_type=None): """ Returns the enabled addresses, as referenced from the IaaS. """ addresses = self.__cyclades.get_server_details(vm_id)['addresses'] results = [] while len(addresses) > 0: key, value = addresses.popitem() if (ip_version is None or value[0]['version'] == ip_version) and \ (connection_type is None or value[0]['OS-EXT-IPS:type'] == connection_type): results.append(value[0]['addr']) return results def __create_floating_ip(self): self.__network_client.floatingips_get() response = self.__network_client.create_floatingip() return response['floating_network_id'] def create_private_network(self): """ Creates a new private network and returns its id """ response = self.__network_client.create_network( type='MAC_FILTERED', name='Deployment network') self.__network_client.create_subnet(network_id=response['id'], enable_dhcp=True, cidr='192.168.0.0/24') return response['id'] def clone(self): new_connector = OkeanosConnector() new_connector.attach_public_ipv4 = self.attach_public_ipv4 new_connector.private_network = self.private_network new_connector.__network_client = self.__network_client new_connector.__cyclades = self.__cyclades return new_connector def cleanup(self): if self.private_network != -1 and self.private_network != 0: self.__wait_until_private_net_is_empty(self.private_network) self.__network_client.delete_network(self.private_network) def __wait_until_private_net_is_empty(self, private_net_id): for i in range(1, MAX_WAIT_FOR_LOOPS): port_set = set() for p in self.__network_client.list_ports(): port_set.add(p['network_id']) if private_net_id not in port_set: return else: sleep(SLEEP_TIMEOUT) def serialize(self): d = dict() d['attach_public_ipv4'] = self.attach_public_ipv4 d['private_network'] = self.private_network return d def deserialize(self, state): self.attach_public_ipv4 = state['attach_public_ipv4'] self.private_network = state['private_network']
def main(): """Parse arguments, use kamaki to create cluster, setup using ansible playbooks""" (opts, args) = parse_arguments(sys.argv[1:]) global CYCLADES, TOKEN, my_vnat_network, my_network_client AUTHENTICATION_URL = opts.cyclades TOKEN = opts.token # Cleanup stale servers from previous runs if opts.show_stale: cleanup_servers(prefix=opts.prefix, delete_stale=opts.delete_stale) return 0 # Initialize a kamaki instance, get endpoints user = AstakosClient(AUTHENTICATION_URL, TOKEN) my_accountData = user.authenticate() endpoints = user.get_endpoints() cyclades_endpoints = user.get_endpoints('compute') cyclades_base_url = parseAstakosEndpoints(endpoints, 'cyclades_compute') cyclades_network_base_url = parseAstakosEndpoints(endpoints, 'cyclades_network') my_cyclades_client = CycladesClient(cyclades_base_url, TOKEN) my_compute_client = ComputeClient(cyclades_base_url, TOKEN) my_network_client = CycladesNetworkClient(cyclades_network_base_url, TOKEN) my_vnat_network = {} # check if 'Hadoop' vnat is created... hadoop_vnat_created = False my_network_dict = my_network_client.list_networks() for n in my_network_dict: if n['name'] == 'Hadoop': hadoop_vnat_created = True my_vnat_network = n # ...else create it if hadoop_vnat_created == False: log.info("Creating vNAT") my_vnat_network = my_network_client.create_network(type='MAC_FILTERED', name='Hadoop'); my_subnet = my_network_client.create_subnet(network_id=my_vnat_network['id'], cidr='192.168.0.0/24'); cnt = int(opts.clustersize) # calculate size of cluster into 'cnt' # Initialize nodes = [] masterName = '' # Create a file to store the root password for later use if not os.path.exists(opts.hadoop_dir+'/bak'): os.makedirs(opts.hadoop_dir+'/bak') pass_fname = opts.hadoop_dir+'/bak/adminPass'+str(datetime.now())[:19].replace(' ', '') adminPass_f = open(pass_fname, 'w') initialClusterSize = 0 server = {} if opts.extend == False: # Create master node (0th node) server = create_machine(opts, my_cyclades_client, 0) if server == {}: return else: servers = my_cyclades_client.list_servers(detail=True) cluster = [s for s in servers if s["name"].startswith(opts.prefix)] initialClusterSize = len(cluster) if initialClusterSize==0: log.info("Cluster cannot be expanded: it does not exist.") return servername = "%s-0" % (opts.prefix) masterName = servername nodes.append(server) # Create slave (worker) nodes if cnt>1 or opts.extend: startingOffset = 1 if opts.extend: startingOffset = initialClusterSize for i in xrange(startingOffset, initialClusterSize+cnt): server = {} server = create_machine(opts, my_cyclades_client, i) if server == {}: return; nodes.append(server) servername = "%s-%d" % (opts.prefix, i) # Write the root password to a file adminPass_f.write('machine = %s, password = %s\n' % (servername, server['adminPass'])) adminPass_f.close() # Setup Hadoop files and settings on all cluster nodes # Create the 'cluster' dictionary out of servers, with only Hadoop-relevant keys (name, ip, integer key) servers = my_cyclades_client.list_servers(detail=True) cluster = [s for s in my_cyclades_client.list_servers(detail=True) if s["name"].startswith(opts.prefix)] cluster0 = [(s["name"], s["attachments"], int(s["name"][s["name"].find('-')+1:])) for s in cluster] cluster0 = sorted(cluster0, key=lambda cluster0: cluster0[2]) cluster = [(cluster0[0][0], cluster0[0][1][2]["ipv4"], cluster0[0][2])] # master IP, different index cluster2 = [(s[0], s[1][1]['ipv4'], int(s[2])) for s in cluster0[1:]] # slave IPs cluster += cluster2 # Prepare Ansible-Hadoop config files (hosts, conf/slaves. vnat/etchosts) hosts = open(opts.hadoop_dir+'/hosts', 'w') hosts.write('[master]\n') etchosts = open(opts.hadoop_dir+'/vnat/etchosts', 'w') for i in xrange(0, initialClusterSize+cnt): for s in cluster: if s[0] == opts.prefix+"-"+str(i): if s[0] == masterName: hosts.write(s[1]+'\n\n'+'[slaves]\n') else: hosts.write(s[1]+'\n') etchosts.write(s[1]+'\t'+s[0]+'\n') hosts.close() etchosts.close() slaves = open(opts.hadoop_dir+'/vnat/slaves', 'w') for s in cluster[1:]: slaves.write(s[0]+'\n') slaves.close() # Execute respective ansible playbook if (opts.extend==False): cmd = "ansible-playbook hadoop_vnat.yml -i hosts -vv --extra-vars \""+"is_master=True, master_node="+cluster[0][0]+" master_ip="+cluster[0][1]+"\""+" -l master" print cmd retval = os.system(cmd) cmd = "ansible-playbook hadoop_vnat.yml -i hosts -vv --extra-vars \""+"is_slave=True, master_node="+cluster[0][0]+" master_ip="+cluster[0][1]+"\""+" -l slaves" print cmd retval = os.system(cmd) slave_ip_list = [] for i in xrange(1, cnt): slave_ip_list.append(cluster[i][0]) enable_ssh_login(cluster[0][1], [cluster[0][0]]) enable_ssh_login(cluster[0][1], slave_ip_list) else: hosts_latest = open(opts.hadoop_dir+'/hosts.latest', 'w') hosts_latest.write('[master]\n') hosts_latest.write(cluster[0][1]+'\n\n'+'[slaves]\n') for i in xrange(initialClusterSize, initialClusterSize+cnt): hosts_latest.write(cluster[i][1]+'\n') hosts_latest.close() # update etc/hosts in all nodes - TODO: de-duplicate entries cmd = "ansible-playbook hadoop_vnat.yml -i hosts -vv --extra-vars \""+"is_master=True, master_ip="+cluster[0][1]+"\""+" -t etchosts" print cmd retval = os.system(cmd) cmd = "ansible-playbook hadoop_vnat.yml -i hosts.latest -vv --extra-vars \""+"is_slave=True, master_node="+cluster[0][0]+" master_ip="+cluster[0][1]+"\""+" -l slaves" print cmd retval = os.system(cmd) slave_ip_list = [] for i in xrange(initialClusterSize, initialClusterSize+cnt): slave_ip_list.append(cluster[i][0]) print "slave_ip_list=", slave_ip_list enable_ssh_login(cluster[0][1], slave_ip_list) # Update conf/slaves in master cmd = "ansible-playbook hadoop_vnat.yml -i hosts -vv --extra-vars \""+"is_master=True, master_ip="+cluster[0][1]+"\""+" -l master -t slaves" print cmd retval = os.system(cmd) log.info("Done.")
# or implied, of GRNET S.A. from kamaki.clients.astakos import AstakosClient from kamaki.clients.cyclades import CycladesNetworkClient # Initialize Astakos AUTHENTICATION_URL = "https://astakos.example.com/identity/v2.0" TOKEN = "User-Token" astakos = AstakosClient(AUTHENTICATION_URL, TOKEN) # Initialize CycladesComputeClient service_type = CycladesNetworkClient.service_type endpoint = astakos.get_endpoint_url(service_type) network = CycladesNetworkClient(endpoint, TOKEN) # Servers server_1 = "id-for-server-1" server_2 = "id-for-server-2" # Create a new network type_ = CycladesNetworkClient.types[0] mynet = network.create_network(type_, name="My Network") # Connect servers to network port_1 = network.create_port(mynet["id"], device_id=server_1) port_2 = network.create_port(mynet["id"], device_id=server_2) # Wait until ready network.wait_port_until(port_1["id"], "ACTIVE") network.wait_port_until(port_2["id"], "ACTIVE")
AUTHENTICATION_URL = "https://astakos.example.com/identity/v2.0" TOKEN = "User-Token" astakos = AstakosClient(AUTHENTICATION_URL, TOKEN) service_type = CycladesComputeClient.service_type endpoint = astakos.get_endpoint_url(service_type) compute = CycladesComputeClient(endpoint, TOKEN) service_type = CycladesNetworkClient.service_type endpoint = astakos.get_endpoint_url(service_type) network = CycladesNetworkClient(endpoint, TOKEN) # Create VPN and reserve an IP type_ = CycladesNetworkClient.types[0] vpn = network.create_network(type_, name="Cluster Network") unused_ips = filter(lambda ip: not ip["port_id"], network.list_floatingips()) ip = unused_ips[0] if unused_ips else network.create_floatingip() ip_net = ip["floating_network_id"] # Server data flavor = 420 image = "image-id-for-a-debian-image" # Create nodes networks = [ dict(uuid=vpn["id"]), ] node_1 = compute.create_server("Node 1", flavor, image, networks=networks) node_2 = compute.create_server("Node 2", flavor, image, networks=networks)
AUTHENTICATION_URL = "https://astakos.example.com/identity/v2.0" TOKEN = "User-Token" astakos = AstakosClient(AUTHENTICATION_URL, TOKEN) service_type = CycladesComputeClient.service_type endpoint = astakos.get_endpoint_url(service_type) compute = CycladesComputeClient(endpoint, TOKEN) service_type = CycladesNetworkClient.service_type endpoint = astakos.get_endpoint_url(service_type) network = CycladesNetworkClient(endpoint, TOKEN) # Create VPN and reserve an IP type_ = CycladesNetworkClient.types[0] vpn = network.create_network(type_, name="Cluster Network") unused_ips = filter(lambda ip: not ip["port_id"], network.list_floatingips()) ip = unused_ips[0] if unused_ips else network.create_floatingip() ip_net = ip["floating_network_id"] # Server data flavor = 420 image = "image-id-for-a-debian-image" # Create nodes networks = [dict(uuid=vpn["id"]), ] node_1 = compute.create_server("Node 1", flavor, image, networks=networks) node_2 = compute.create_server("Node 2", flavor, image, networks=networks) # Create gateway networks.append(dict(uuid=ip_net, fixed_ip=ip["floating_ip_address"]))
class OkeanosConnector(AbstractConnector): """ Okeanos connector. """ def __init__(self): AbstractConnector.__init__(self) self.__cyclades = None self.__network_client = None self.attach_public_ipv4 = False self.private_network = -1 def authenticate(self, authentication=None): """ :param authentication: :return: """ if self.__cyclades is not None: return True try: authcl = AstakosClient(authentication['URL'], authentication['TOKEN']) authcl.authenticate() self.__cyclades = CycladesClient(authcl.get_service_endpoints('compute')['publicURL'], authentication['TOKEN']) self.__network_client = CycladesNetworkClient(authcl.get_service_endpoints('network')['publicURL'], authentication['TOKEN']) except ClientError: stderr.write('Connector initialization failed') return False return True def configure(self, configuration): self.authenticate(configuration['auth']) if 'private_network' in configuration and configuration['private_network']: self.private_network = 0 if 'attach_public_ipv4' in configuration and configuration['attach_public_ipv4']: self.attach_public_ipv4 = True def prepare(self): """ In this method, application-level IaaS related actions are executed. :return: """ if self.private_network == 0: self.private_network = self.create_private_network() def create_vm(self, name, flavor_id, image_id): """ :param name: :param flavor_id: :param image_id: :return: """ networks = [] if self.attach_public_ipv4: networks.append({'uuid': self.__create_floating_ip()}) if self.private_network != -1: networks.append({'uuid': self.private_network}) response = self.__cyclades.create_server(name=name, flavor_id=flavor_id, image_id=image_id, networks=networks) ret_value = dict() ret_value['password'] = response['adminPass'] ret_value['id'] = response['id'] ret_value['user'] = response['metadata']['users'] ret_value['hostname'] = 'snf-' + str(response['id']) + '.vm.okeanos.grnet.gr' self.__cyclades.wait_server(server_id=ret_value['id'], current_status='ACTIVE') return ret_value def delete_vm(self, server_id): """ Delete VM method. The method is blocking until the VM goes to a "DELETED" state :param server_id: :return: """ attachments = self.__cyclades.get_server_details(server_id)['attachments'] port_id = None for a in attachments: if a['OS-EXT-IPS:type'] == 'floating': port_id = a['id'] floating_ip_id = None for ip in self.__network_client.list_floatingips(): if port_id is not None and ip['port_id'] == str(port_id): floating_ip_id = ip['id'] self.__cyclades.delete_server(server_id) self.__cyclades.wait_server(server_id, current_status='DELETED') # wait until server is deleted if floating_ip_id is not None: self.__wait_until_ip_released(floating_ip_id) self.__network_client.delete_floatingip(floating_ip_id) def __wait_until_ip_released(self, floating_ip_id): for i in range(1, MAX_WAIT_FOR_LOOPS+1): for ip in self.__network_client.list_floatingips(): if ip['id'] == floating_ip_id: if ip['instance_id'] is None or ip['instance_id'] == 'None': return True sleep(SLEEP_TIMEOUT) def list_vms(self): """ :return: """ return self.__cyclades.list_servers() def get_status(self, vm_id): """ :param vm_id: :return: """ return self.__cyclades.get_server_details(vm_id) def get_server_addresses(self, vm_id, ip_version=None, connection_type=None): """ Returns the enabled addresses, as referenced from the IaaS. """ addresses = self.__cyclades.get_server_details(vm_id)['addresses'] results = [] while len(addresses) > 0: key, value = addresses.popitem() if (ip_version is None or value[0]['version'] == ip_version) and \ (connection_type is None or value[0]['OS-EXT-IPS:type'] == connection_type): results.append(value[0]['addr']) return results def __create_floating_ip(self): self.__network_client.floatingips_get() response = self.__network_client.create_floatingip() return response['floating_network_id'] def create_private_network(self): """ Creates a new private network and returns its id """ response = self.__network_client.create_network(type='MAC_FILTERED', name='Deployment network') self.__network_client.create_subnet( network_id=response['id'], enable_dhcp=True, cidr='192.168.0.0/24' ) return response['id'] def clone(self): new_connector = OkeanosConnector() new_connector.attach_public_ipv4 = self.attach_public_ipv4 new_connector.private_network = self.private_network new_connector.__network_client = self.__network_client new_connector.__cyclades = self.__cyclades return new_connector def cleanup(self): if self.private_network != -1 and self.private_network != 0: self.__wait_until_private_net_is_empty(self.private_network) self.__network_client.delete_network(self.private_network) def __wait_until_private_net_is_empty(self, private_net_id): for i in range(1, MAX_WAIT_FOR_LOOPS): port_set = set() for p in self.__network_client.list_ports(): port_set.add(p['network_id']) if private_net_id not in port_set: return else: sleep(SLEEP_TIMEOUT) def serialize(self): d = dict() d['attach_public_ipv4'] = self.attach_public_ipv4 d['private_network'] = self.private_network return d def deserialize(self, state): self.attach_public_ipv4 = state['attach_public_ipv4'] self.private_network = state['private_network']