def __init__(self, *args, **kwargs): if kwargs.get('gce_driver'): self.gce = kwargs['gce_driver'] else: self.gce = GCENodeDriver(*args, **kwargs) self.connection = self.gce.connection
def setUp(self): GCEMockHttp.test = self GCENodeDriver.connectionCls.conn_classes = (GCEMockHttp, GCEMockHttp) GoogleBaseAuthConnection.conn_classes = (GoogleAuthMockHttp, GoogleAuthMockHttp) GCEMockHttp.type = None kwargs = GCE_KEYWORD_PARAMS.copy() kwargs['auth_type'] = 'IA' kwargs['datacenter'] = self.datacenter self.driver = GCENodeDriver(*GCE_PARAMS, **kwargs)
def __init__(self, config, gcp_credentials_file): self.config = config creds = read_json(gcp_credentials_file) self._compute = GCENodeDriver( creds['client_email'], gcp_credentials_file, project=creds['project_id'], datacenter=self.config['gcp_compute_zone'], timeout=self.config['compute_timeout']) self._dns = GoogleDNSDriver(creds['client_email'], gcp_credentials_file, project=creds['project_id']) self._dns_zone = self._dns.get_zone(config['gcp_dns_zone']) self.log = logging.getLogger(__name__ + '.' + self._name)
class GCELBDriver(Driver): connectionCls = GCEConnection apiname = 'googleapis' name = 'Google Compute Engine Load Balancer' website = 'https://cloud.google.com/' _VALUE_TO_ALGORITHM_MAP = {'RANDOM': Algorithm.RANDOM} def __init__(self, *args, **kwargs): if kwargs.get('gce_driver'): self.gce = kwargs['gce_driver'] else: self.gce = GCENodeDriver(*args, **kwargs) self.connection = self.gce.connection def _get_node_from_ip(self, ip): """ Return the node object that matches a given public IP address. :param ip: Public IP address to search for :type ip: ``str`` :return: Node object that has the given IP, or None if not found. :rtype: :class:`Node` or None """ all_nodes = self.gce.list_nodes(ex_zone='all') for node in all_nodes: if ip in node.public_ips: return node return None def list_protocols(self): """ Return a list of supported protocols. For GCE, this is simply a hardcoded list. :rtype: ``list`` of ``str`` """ return ['TCP', 'UDP'] def list_balancers(self, ex_region=None): """ List all loadbalancers :keyword ex_region: The region to return balancers from. If None, will default to self.region. If 'all', will return all balancers. :type ex_region: ``str`` or :class:`GCERegion` or ``None`` :rtype: ``list`` of :class:`LoadBalancer` """ balancers = [] for fwr in self.gce.ex_list_forwarding_rules(region=ex_region): balancers.append(self._forwarding_rule_to_loadbalancer(fwr)) return balancers def create_balancer(self, name, port, protocol, algorithm, members, ex_region=None, ex_healthchecks=None, ex_address=None, ex_session_affinity=None): """ Create a new load balancer instance. For GCE, this means creating a forwarding rule and a matching target pool, then adding the members to the target pool. :param name: Name of the new load balancer (required) :type name: ``str`` :param port: Port or range of ports the load balancer should listen on, defaults to all ports. Examples: '80', '5000-5999' :type port: ``str`` :param protocol: Load balancer protocol. Should be 'tcp' or 'udp', defaults to 'tcp'. :type protocol: ``str`` :param members: List of Members to attach to balancer. Can be Member objects or Node objects. Node objects are preferred for GCE, but Member objects are accepted to comply with the established libcloud API. Note that the 'port' attribute of the members is ignored. :type members: ``list`` of :class:`Member` or :class:`Node` :param algorithm: Load balancing algorithm. Ignored for GCE which uses a hashing-based algorithm. :type algorithm: :class:`Algorithm` or ``None`` :keyword ex_region: Optional region to create the load balancer in. Defaults to the default region of the GCE Node Driver. :type ex_region: C{GCERegion} or ``str`` :keyword ex_healthchecks: Optional list of healthcheck objects or names to add to the load balancer. :type ex_healthchecks: ``list`` of :class:`GCEHealthCheck` or ``list`` of ``str`` :keyword ex_address: Optional static address object to be assigned to the load balancer. :type ex_address: C{GCEAddress} :keyword ex_session_affinity: Optional algorithm to use for session affinity. This will modify the hashing algorithm such that a client will tend to stick to a particular Member. :type ex_session_affinity: ``str`` :return: LoadBalancer object :rtype: :class:`LoadBalancer` """ node_list = [] for member in members: # Member object if hasattr(member, 'ip'): if member.extra.get('node'): node_list.append(member.extra['node']) else: node_list.append(self._get_node_from_ip(member.ip)) # Node object elif hasattr(member, 'name'): node_list.append(member) # Assume it's a node name otherwise else: node_list.append(self.gce.ex_get_node(member, 'all')) # Create Target Pool tp_name = '%s-tp' % name targetpool = self.gce.ex_create_targetpool( tp_name, region=ex_region, healthchecks=ex_healthchecks, nodes=node_list, session_affinity=ex_session_affinity) # Create the Forwarding rule, but if it fails, delete the target pool. try: forwarding_rule = self.gce.ex_create_forwarding_rule( name, targetpool, region=ex_region, protocol=protocol, port_range=port, address=ex_address) except: targetpool.destroy() raise # Reformat forwarding rule to LoadBalancer object return self._forwarding_rule_to_loadbalancer(forwarding_rule) def destroy_balancer(self, balancer): """ Destroy a load balancer. For GCE, this means destroying the associated forwarding rule, then destroying the target pool that was attached to the forwarding rule. :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :return: True if successful :rtype: ``bool`` """ destroy = balancer.extra['forwarding_rule'].destroy() if destroy: tp_destroy = balancer.extra['targetpool'].destroy() return tp_destroy else: return destroy def get_balancer(self, balancer_id): """ Return a :class:`LoadBalancer` object. :param balancer_id: Name of load balancer you wish to fetch. For GCE, this is the name of the associated forwarding rule. :param balancer_id: ``str`` :rtype: :class:`LoadBalancer` """ fwr = self.gce.ex_get_forwarding_rule(balancer_id) return self._forwarding_rule_to_loadbalancer(fwr) def balancer_attach_compute_node(self, balancer, node): """ Attach a compute node as a member to the load balancer. :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param node: Node to join to the balancer :type node: :class:`Node` :return: Member after joining the balancer. :rtype: :class:`Member` """ add_node = balancer.extra['targetpool'].add_node(node) if add_node: return self._node_to_member(node, balancer) def balancer_attach_member(self, balancer, member): """ Attach a member to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param member: Member to join to the balancer :type member: :class:`Member` :return: Member after joining the balancer. :rtype: :class:`Member` """ node = member.extra.get('node') or self._get_node_from_ip(member.ip) add_node = balancer.extra['targetpool'].add_node(node) if add_node: return self._node_to_member(node, balancer) def balancer_detach_member(self, balancer, member): """ Detach member from balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param member: Member which should be used :type member: :class:`Member` :return: True if member detach was successful, otherwise False :rtype: ``bool`` """ node = member.extra.get('node') or self._get_node_from_ip(member.ip) remove_node = balancer.extra['targetpool'].remove_node(node) return remove_node def balancer_list_members(self, balancer): """ Return list of members attached to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :rtype: ``list`` of :class:`Member` """ return [ self._node_to_member(n, balancer) for n in balancer.extra['targetpool'].nodes ] def ex_create_healthcheck(self, *args, **kwargs): return self.gce.ex_create_healthcheck(*args, **kwargs) def ex_list_healthchecks(self): return self.gce.ex_list_healthchecks() def ex_balancer_attach_healthcheck(self, balancer, healthcheck): """ Attach a healthcheck to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param healthcheck: Healthcheck to add :type healthcheck: :class:`GCEHealthCheck` :return: True if successful :rtype: ``bool`` """ return balancer.extra['targetpool'].add_healthcheck(healthcheck) def ex_balancer_detach_healthcheck(self, balancer, healthcheck): """ Detach healtcheck from balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param healthcheck: Healthcheck to remove :type healthcheck: :class:`GCEHealthCheck` :return: True if successful :rtype: ``bool`` """ return balancer.extra['targetpool'].remove_healthcheck(healthcheck) def ex_balancer_list_healthchecks(self, balancer): """ Return list of healthchecks attached to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :rtype: ``list`` of :class:`HealthChecks` """ return balancer.extra['healthchecks'] def _node_to_member(self, node, balancer): """ Return a Member object based on a Node. :param node: Node object :type node: :class:`Node` :keyword balancer: The balancer the member is attached to. :type balancer: :class:`LoadBalancer` :return: Member object :rtype: :class:`Member` """ # A balancer can have a node as a member, even if the node doesn't # exist. In this case, 'node' is simply a string to where the resource # would be found if it was there. if hasattr(node, 'name'): member_id = node.name else: member_id = node if hasattr(node, 'public_ips') and len(node.public_ips) > 0: member_ip = node.public_ips[0] else: member_ip = None extra = {'node': node} return Member(id=member_id, ip=member_ip, port=balancer.port, balancer=balancer, extra=extra) def _forwarding_rule_to_loadbalancer(self, forwarding_rule): """ Return a Load Balancer object based on a GCEForwardingRule object. :param forwarding_rule: ForwardingRule object :type forwarding_rule: :class:`GCEForwardingRule` :return: LoadBalancer object :rtype: :class:`LoadBalancer` """ extra = {} extra['forwarding_rule'] = forwarding_rule extra['targetpool'] = forwarding_rule.targetpool extra['healthchecks'] = forwarding_rule.targetpool.healthchecks return LoadBalancer(id=forwarding_rule.id, name=forwarding_rule.name, state=None, ip=forwarding_rule.address, port=forwarding_rule.extra['portRange'], driver=self, extra=extra)
class GCELBDriver(Driver): connectionCls = GCEConnection apiname = 'googleapis' name = 'Google Compute Engine Load Balancer' website = 'https://cloud.google.com/' _VALUE_TO_ALGORITHM_MAP = { 'RANDOM': Algorithm.RANDOM } def __init__(self, *args, **kwargs): if kwargs.get('gce_driver'): self.gce = kwargs['gce_driver'] else: self.gce = GCENodeDriver(*args, **kwargs) self.connection = self.gce.connection def _get_node_from_ip(self, ip): """ Return the node object that matches a given public IP address. :param ip: Public IP address to search for :type ip: ``str`` :return: Node object that has the given IP, or None if not found. :rtype: :class:`Node` or None """ all_nodes = self.gce.list_nodes(ex_zone='all') for node in all_nodes: if ip in node.public_ips: return node return None def list_protocols(self): """ Return a list of supported protocols. For GCE, this is simply a hardcoded list. :rtype: ``list`` of ``str`` """ return ['TCP', 'UDP'] def list_balancers(self, ex_region=None): """ List all loadbalancers :keyword ex_region: The region to return balancers from. If None, will default to self.region. If 'all', will return all balancers. :type ex_region: ``str`` or :class:`GCERegion` or ``None`` :rtype: ``list`` of :class:`LoadBalancer` """ balancers = [] for fwr in self.gce.ex_list_forwarding_rules(region=ex_region): balancers.append(self._forwarding_rule_to_loadbalancer(fwr)) return balancers def create_balancer(self, name, port, protocol, algorithm, members, ex_region=None, ex_healthchecks=None, ex_address=None, ex_session_affinity=None): """ Create a new load balancer instance. For GCE, this means creating a forwarding rule and a matching target pool, then adding the members to the target pool. :param name: Name of the new load balancer (required) :type name: ``str`` :param port: Port or range of ports the load balancer should listen on, defaults to all ports. Examples: '80', '5000-5999' :type port: ``str`` :param protocol: Load balancer protocol. Should be 'tcp' or 'udp', defaults to 'tcp'. :type protocol: ``str`` :param members: List of Members to attach to balancer. Can be Member objects or Node objects. Node objects are preferred for GCE, but Member objects are accepted to comply with the established libcloud API. Note that the 'port' attribute of the members is ignored. :type members: ``list`` of :class:`Member` or :class:`Node` :param algorithm: Load balancing algorithm. Ignored for GCE which uses a hashing-based algorithm. :type algorithm: :class:`Algorithm` or ``None`` :keyword ex_region: Optional region to create the load balancer in. Defaults to the default region of the GCE Node Driver. :type ex_region: C{GCERegion} or ``str`` :keyword ex_healthchecks: Optional list of healthcheck objects or names to add to the load balancer. :type ex_healthchecks: ``list`` of :class:`GCEHealthCheck` or ``list`` of ``str`` :keyword ex_address: Optional static address object to be assigned to the load balancer. :type ex_address: C{GCEAddress} :keyword ex_session_affinity: Optional algorithm to use for session affinity. This will modify the hashing algorithm such that a client will tend to stick to a particular Member. :type ex_session_affinity: ``str`` :return: LoadBalancer object :rtype: :class:`LoadBalancer` """ node_list = [] for member in members: # Member object if hasattr(member, 'ip'): if member.extra.get('node'): node_list.append(member.extra['node']) else: node_list.append(self._get_node_from_ip(member.ip)) # Node object elif hasattr(member, 'name'): node_list.append(member) # Assume it's a node name otherwise else: node_list.append(self.gce.ex_get_node(member, 'all')) # Create Target Pool tp_name = '%s-tp' % name targetpool = self.gce.ex_create_targetpool( tp_name, region=ex_region, healthchecks=ex_healthchecks, nodes=node_list, session_affinity=ex_session_affinity) # Create the Forwarding rule, but if it fails, delete the target pool. try: forwarding_rule = self.gce.ex_create_forwarding_rule( name, targetpool, region=ex_region, protocol=protocol, port_range=port, address=ex_address) except: targetpool.destroy() raise # Reformat forwarding rule to LoadBalancer object return self._forwarding_rule_to_loadbalancer(forwarding_rule) def destroy_balancer(self, balancer): """ Destroy a load balancer. For GCE, this means destroying the associated forwarding rule, then destroying the target pool that was attached to the forwarding rule. :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :return: True if successful :rtype: ``bool`` """ destroy = balancer.extra['forwarding_rule'].destroy() if destroy: tp_destroy = balancer.extra['targetpool'].destroy() return tp_destroy else: return destroy def get_balancer(self, balancer_id): """ Return a :class:`LoadBalancer` object. :param balancer_id: Name of load balancer you wish to fetch. For GCE, this is the name of the associated forwarding rule. :param balancer_id: ``str`` :rtype: :class:`LoadBalancer` """ fwr = self.gce.ex_get_forwarding_rule(balancer_id) return self._forwarding_rule_to_loadbalancer(fwr) def balancer_attach_compute_node(self, balancer, node): """ Attach a compute node as a member to the load balancer. :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param node: Node to join to the balancer :type node: :class:`Node` :return: Member after joining the balancer. :rtype: :class:`Member` """ add_node = balancer.extra['targetpool'].add_node(node) if add_node: return self._node_to_member(node, balancer) def balancer_attach_member(self, balancer, member): """ Attach a member to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param member: Member to join to the balancer :type member: :class:`Member` :return: Member after joining the balancer. :rtype: :class:`Member` """ node = member.extra.get('node') or self._get_node_from_ip(member.ip) add_node = balancer.extra['targetpool'].add_node(node) if add_node: return self._node_to_member(node, balancer) def balancer_detach_member(self, balancer, member): """ Detach member from balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param member: Member which should be used :type member: :class:`Member` :return: True if member detach was successful, otherwise False :rtype: ``bool`` """ node = member.extra.get('node') or self._get_node_from_ip(member.ip) remove_node = balancer.extra['targetpool'].remove_node(node) return remove_node def balancer_list_members(self, balancer): """ Return list of members attached to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :rtype: ``list`` of :class:`Member` """ return [self._node_to_member(n, balancer) for n in balancer.extra['targetpool'].nodes] def ex_create_healthcheck(self, *args, **kwargs): return self.gce.ex_create_healthcheck(*args, **kwargs) def ex_list_healthchecks(self): return self.gce.ex_list_healthchecks() def ex_balancer_attach_healthcheck(self, balancer, healthcheck): """ Attach a healthcheck to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param healthcheck: Healthcheck to add :type healthcheck: :class:`GCEHealthCheck` :return: True if successful :rtype: ``bool`` """ return balancer.extra['targetpool'].add_healthcheck(healthcheck) def ex_balancer_detach_healthcheck(self, balancer, healthcheck): """ Detach healtcheck from balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :param healthcheck: Healthcheck to remove :type healthcheck: :class:`GCEHealthCheck` :return: True if successful :rtype: ``bool`` """ return balancer.extra['targetpool'].remove_healthcheck(healthcheck) def ex_balancer_list_healthchecks(self, balancer): """ Return list of healthchecks attached to balancer :param balancer: LoadBalancer which should be used :type balancer: :class:`LoadBalancer` :rtype: ``list`` of :class:`HealthChecks` """ return balancer.extra['healthchecks'] def _node_to_member(self, node, balancer): """ Return a Member object based on a Node. :param node: Node object :type node: :class:`Node` :keyword balancer: The balancer the member is attached to. :type balancer: :class:`LoadBalancer` :return: Member object :rtype: :class:`Member` """ # A balancer can have a node as a member, even if the node doesn't # exist. In this case, 'node' is simply a string to where the resource # would be found if it was there. if hasattr(node, 'name'): member_id = node.name else: member_id = node if hasattr(node, 'public_ips') and len(node.public_ips) > 0: member_ip = node.public_ips[0] else: member_ip = None extra = {'node': node} return Member(id=member_id, ip=member_ip, port=balancer.port, balancer=balancer, extra=extra) def _forwarding_rule_to_loadbalancer(self, forwarding_rule): """ Return a Load Balancer object based on a GCEForwardingRule object. :param forwarding_rule: ForwardingRule object :type forwarding_rule: :class:`GCEForwardingRule` :return: LoadBalancer object :rtype: :class:`LoadBalancer` """ extra = {} extra['forwarding_rule'] = forwarding_rule extra['targetpool'] = forwarding_rule.targetpool extra['healthchecks'] = forwarding_rule.targetpool.healthchecks return LoadBalancer(id=forwarding_rule.id, name=forwarding_rule.name, state=None, ip=forwarding_rule.address, port=forwarding_rule.extra['portRange'], driver=self, extra=extra)
class GCENodeDriverTest(LibcloudTestCase, TestCaseMixin): """ Google Compute Engine Test Class. """ # Mock out a few specific calls that interact with the user, system or # environment. GoogleBaseConnection._get_token_info_from_file = lambda x: None GoogleBaseConnection._write_token_info_to_file = lambda x: None GoogleInstalledAppAuthConnection.get_code = lambda x: '1234' GCEZone._now = lambda x: datetime.datetime(2013, 6, 26, 19, 0, 0) datacenter = 'us-central1-a' def setUp(self): GCEMockHttp.test = self GCENodeDriver.connectionCls.conn_classes = (GCEMockHttp, GCEMockHttp) GoogleBaseAuthConnection.conn_classes = (GoogleAuthMockHttp, GoogleAuthMockHttp) GCEMockHttp.type = None kwargs = GCE_KEYWORD_PARAMS.copy() kwargs['auth_type'] = 'IA' kwargs['datacenter'] = self.datacenter self.driver = GCENodeDriver(*GCE_PARAMS, **kwargs) def test_timestamp_to_datetime(self): timestamp1 = '2013-06-26T10:05:19.340-07:00' datetime1 = datetime.datetime(2013, 6, 26, 17, 5, 19) self.assertEqual(timestamp_to_datetime(timestamp1), datetime1) timestamp2 = '2013-06-26T17:43:15.000-00:00' datetime2 = datetime.datetime(2013, 6, 26, 17, 43, 15) self.assertEqual(timestamp_to_datetime(timestamp2), datetime2) def test_find_zone(self): zone1 = self.driver._find_zone('libcloud-demo-np-node', 'instances') self.assertEqual(zone1, 'us-central1-a') zone2 = self.driver._find_zone('libcloud-demo-europe-np-node', 'instances') self.assertEqual(zone2, 'europe-west1-a') region = self.driver._find_zone('libcloud-demo-address', 'addresses', region=True) self.assertEqual(region, 'us-central1') def test_match_images(self): project = 'debian-cloud' image = self.driver._match_images(project, 'debian-7') self.assertEqual(image.name, 'debian-7-wheezy-v20130617') image = self.driver._match_images(project, 'debian-6') self.assertEqual(image.name, 'debian-6-squeeze-v20130617') def test_ex_list_addresses(self): address_list = self.driver.ex_list_addresses() address_list_all = self.driver.ex_list_addresses('all') address_list_uc1 = self.driver.ex_list_addresses('us-central1') self.assertEqual(len(address_list), 2) self.assertEqual(len(address_list_all), 4) self.assertEqual(address_list[0].name, 'libcloud-demo-address') self.assertEqual(address_list_uc1[0].name, 'libcloud-demo-address') self.assertEqual(address_list_all[0].name, 'lcaddress') def test_ex_list_firewalls(self): firewalls = self.driver.ex_list_firewalls() self.assertEqual(len(firewalls), 4) self.assertEqual(firewalls[0].name, 'default-allow-internal') def test_list_images(self): local_images = self.driver.list_images() debian_images = self.driver.list_images(ex_project='debian-cloud') self.assertEqual(len(local_images), 1) self.assertEqual(len(debian_images), 10) self.assertEqual(local_images[0].name, 'debian-7-wheezy-v20130617') def test_list_locations(self): locations = self.driver.list_locations() self.assertEqual(len(locations), 5) self.assertEqual(locations[0].name, 'europe-west1-a') def test_ex_list_networks(self): networks = self.driver.ex_list_networks() self.assertEqual(len(networks), 3) self.assertEqual(networks[0].name, 'default') def test_list_nodes(self): nodes = self.driver.list_nodes() nodes_all = self.driver.list_nodes(ex_zone='all') nodes_uc1a = self.driver.list_nodes(ex_zone='us-central1-a') self.assertEqual(len(nodes), 5) self.assertEqual(len(nodes_all), 8) self.assertEqual(len(nodes_uc1a), 5) self.assertEqual(nodes[0].name, 'node-name') self.assertEqual(nodes_uc1a[0].name, 'node-name') self.assertEqual(nodes_all[0].name, 'libcloud-demo-persist-node') def test_list_sizes(self): sizes = self.driver.list_sizes() sizes_all = self.driver.list_sizes('all') self.assertEqual(len(sizes), 22) self.assertEqual(len(sizes_all), 100) self.assertEqual(sizes[0].name, 'f1-micro') self.assertEqual(sizes[0].extra['zone'].name, 'us-central1-a') self.assertEqual(sizes_all[0].name, 'n1-highmem-8') self.assertEqual(sizes_all[0].extra['zone'].name, 'us-central1-a') def test_list_volumes(self): volumes = self.driver.list_volumes() volumes_all = self.driver.list_volumes('all') volumes_uc1a = self.driver.list_volumes('us-central1-a') self.assertEqual(len(volumes), 3) self.assertEqual(len(volumes_all), 3) self.assertEqual(len(volumes_uc1a), 3) self.assertEqual(volumes[0].name, 'lcdisk') self.assertEqual(volumes_all[0].name, 'test-disk') self.assertEqual(volumes_uc1a[0].name, 'lcdisk') def test_ex_list_zones(self): zones = self.driver.ex_list_zones() self.assertEqual(len(zones), 5) self.assertEqual(zones[0].name, 'europe-west1-a') def test_ex_create_address(self): address_name = 'lcaddress' address = self.driver.ex_create_address(address_name) self.assertTrue(isinstance(address, GCEAddress)) self.assertEqual(address.name, address_name) def test_ex_create_firewall(self): firewall_name = 'lcfirewall' allowed = [{'IPProtocol': 'tcp', 'ports': ['4567']}] source_tags = ['libcloud'] firewall = self.driver.ex_create_firewall(firewall_name, allowed, source_tags=source_tags) self.assertTrue(isinstance(firewall, GCEFirewall)) self.assertEqual(firewall.name, firewall_name) def test_ex_create_network(self): network_name = 'lcnetwork' cidr = '10.11.0.0/16' network = self.driver.ex_create_network(network_name, cidr) self.assertTrue(isinstance(network, GCENetwork)) self.assertEqual(network.name, network_name) self.assertEqual(network.cidr, cidr) def test_create_node_req(self): image = self.driver.ex_get_image('debian-7') size = self.driver.ex_get_size('n1-standard-1') location = self.driver.zone network = self.driver.ex_get_network('default') tags = ['libcloud'] metadata = [{'key': 'test_key', 'value': 'test_value'}] boot_disk = self.driver.ex_get_volume('lcdisk') node_request, node_data = self.driver._create_node_req( 'lcnode', size, image, location, network, tags, metadata, boot_disk) self.assertEqual(node_request, '/zones/%s/instances' % location.name) self.assertEqual(node_data['metadata'][0]['key'], 'test_key') self.assertEqual(node_data['tags']['items'][0], 'libcloud') self.assertEqual(node_data['name'], 'lcnode') self.assertTrue(node_data['disks'][0]['boot']) def test_create_node(self): node_name = 'node-name' image = self.driver.ex_get_image('debian-7') size = self.driver.ex_get_size('n1-standard-1') node = self.driver.create_node(node_name, size, image) self.assertTrue(isinstance(node, Node)) self.assertEqual(node.name, node_name) def test_create_node_existing(self): node_name = 'libcloud-demo-europe-np-node' image = self.driver.ex_get_image('debian-7') size = self.driver.ex_get_size('n1-standard-1', zone='europe-west1-a') self.assertRaises(ResourceExistsError, self.driver.create_node, node_name, size, image, location='europe-west1-a') def test_ex_create_multiple_nodes(self): base_name = 'lcnode' image = self.driver.ex_get_image('debian-7') size = self.driver.ex_get_size('n1-standard-1') number = 2 nodes = self.driver.ex_create_multiple_nodes(base_name, size, image, number) self.assertEqual(len(nodes), 2) self.assertTrue(isinstance(nodes[0], Node)) self.assertTrue(isinstance(nodes[1], Node)) self.assertEqual(nodes[0].name, '%s-000' % base_name) self.assertEqual(nodes[1].name, '%s-001' % base_name) def test_create_volume(self): volume_name = 'lcdisk' size = 1 volume = self.driver.create_volume(size, volume_name) self.assertTrue(isinstance(volume, StorageVolume)) self.assertEqual(volume.name, volume_name) def test_ex_update_firewall(self): firewall_name = 'lcfirewall' firewall = self.driver.ex_get_firewall(firewall_name) firewall.source_ranges = ['10.0.0.0/16'] firewall.source_tags = ['libcloud', 'test'] firewall2 = self.driver.ex_update_firewall(firewall) self.assertTrue(isinstance(firewall2, GCEFirewall)) def test_reboot_node(self): node = self.driver.ex_get_node('node-name') reboot = self.driver.reboot_node(node) self.assertTrue(reboot) def test_ex_set_node_tags(self): new_tags = ['libcloud'] node = self.driver.ex_get_node('node-name') set_tags = self.driver.ex_set_node_tags(node, new_tags) self.assertTrue(set_tags) def test_attach_volume(self): volume = self.driver.ex_get_volume('lcdisk') node = self.driver.ex_get_node('node-name') attach = volume.attach(node) self.assertTrue(attach) def test_detach_volume(self): volume = self.driver.ex_get_volume('lcdisk') node = self.driver.ex_get_node('node-name') # This fails since the node is required detach = volume.detach() self.assertFalse(detach) # This should pass detach = self.driver.detach_volume(volume, node) self.assertTrue(detach) def test_ex_destroy_address(self): address = self.driver.ex_get_address('lcaddress') destroyed = address.destroy() self.assertTrue(destroyed) def test_ex_destroy_firewall(self): firewall = self.driver.ex_get_firewall('lcfirewall') destroyed = firewall.destroy() self.assertTrue(destroyed) def test_ex_destroy_network(self): network = self.driver.ex_get_network('lcnetwork') destroyed = network.destroy() self.assertTrue(destroyed) def test_destroy_node(self): node = self.driver.ex_get_node('node-name') destroyed = node.destroy() self.assertTrue(destroyed) def test_ex_destroy_multiple_nodes(self): nodes = [] nodes.append(self.driver.ex_get_node('lcnode-000')) nodes.append(self.driver.ex_get_node('lcnode-001')) destroyed = self.driver.ex_destroy_multiple_nodes(nodes) for d in destroyed: self.assertTrue(d) def test_destroy_volume(self): address = self.driver.ex_get_address('lcaddress') destroyed = address.destroy() self.assertTrue(destroyed) def test_ex_get_address(self): address_name = 'lcaddress' address = self.driver.ex_get_address(address_name) self.assertEqual(address.name, address_name) self.assertEqual(address.address, '173.255.113.20') self.assertEqual(address.region, 'us-central1') self.assertEqual(address.extra['status'], 'RESERVED') def test_ex_get_firewall(self): firewall_name = 'lcfirewall' firewall = self.driver.ex_get_firewall(firewall_name) self.assertEqual(firewall.name, firewall_name) self.assertEqual(firewall.network.name, 'default') self.assertEqual(firewall.source_tags, ['libcloud']) def test_ex_get_image(self): partial_name = 'debian-7' image = self.driver.ex_get_image(partial_name) self.assertEqual(image.name, 'debian-7-wheezy-v20130617') # A 'debian-7' image exists in the local project self.assertTrue(image.extra['description'].startswith('Local')) partial_name = 'debian-6' image = self.driver.ex_get_image(partial_name) self.assertEqual(image.name, 'debian-6-squeeze-v20130617') self.assertTrue(image.extra['description'].startswith('Debian')) def test_ex_get_network(self): network_name = 'lcnetwork' network = self.driver.ex_get_network(network_name) self.assertEqual(network.name, network_name) self.assertEqual(network.cidr, '10.11.0.0/16') self.assertEqual(network.extra['gatewayIPv4'], '10.11.0.1') def test_ex_get_project(self): project = self.driver.ex_get_project() self.assertEqual(project.name, 'project_name') instances_quota = project.quotas[0] self.assertEqual(instances_quota['usage'], 7.0) self.assertEqual(instances_quota['limit'], 8.0) def test_ex_get_size(self): size_name = 'n1-standard-1' size = self.driver.ex_get_size(size_name) self.assertEqual(size.name, size_name) self.assertEqual(size.extra['zone'].name, 'us-central1-a') self.assertEqual(size.disk, 10) self.assertEqual(size.ram, 3840) self.assertEqual(size.extra['guestCpus'], 1) def test_ex_get_volume(self): volume_name = 'lcdisk' volume = self.driver.ex_get_volume(volume_name) self.assertEqual(volume.name, volume_name) self.assertEqual(volume.size, '1') self.assertEqual(volume.extra['status'], 'READY') def test_ex_get_zone(self): zone_name = 'us-central1-a' expected_time_until = datetime.timedelta(days=52) expected_duration = datetime.timedelta(days=15) zone = self.driver.ex_get_zone(zone_name) self.assertEqual(zone.name, zone_name) self.assertEqual(zone.time_until_mw, expected_time_until) self.assertEqual(zone.next_mw_duration, expected_duration)