فهرست منبع

Renamed instancetype to vmtype

Nuwan Goonasekera 8 سال پیش
والد
کامیت
7ac29d66d3
2فایلهای تغییر یافته به همراه210 افزوده شده و 108 حذف شده
  1. 192 88
      cloudbridge/cloud/providers/azure/resources.py
  2. 18 20
      cloudbridge/cloud/providers/azure/services.py

+ 192 - 88
cloudbridge/cloud/providers/azure/resources.py

@@ -6,19 +6,21 @@ import json
 import logging
 import logging
 import time
 import time
 
 
+
 from azure.common import AzureException
 from azure.common import AzureException
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import NetworkSecurityGroup
 
 
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
     BaseBucket, BaseBucketObject, BaseFloatingIP, \
     BaseBucket, BaseBucketObject, BaseFloatingIP, \
-    BaseInstance, BaseInstanceType, BaseKeyPair, \
-    BaseLaunchConfig, BaseMachineImage, BaseNetwork, \
+    BaseInstance, BaseInternetGateway, \
+    BaseKeyPair, BaseLaunchConfig, BaseMachineImage, BaseNetwork, \
     BasePlacementZone, BaseRegion, BaseRouter, BaseSecurityGroup, \
     BasePlacementZone, BaseRegion, BaseRouter, BaseSecurityGroup, \
     BaseSecurityGroupRule, BaseSnapshot, BaseSubnet, \
     BaseSecurityGroupRule, BaseSnapshot, BaseSubnet, \
-    BaseVolume, ClientPagedResultList
+    BaseVMType, BaseVolume, ClientPagedResultList
 from cloudbridge.cloud.interfaces import InstanceState, VolumeState
 from cloudbridge.cloud.interfaces import InstanceState, VolumeState
 from cloudbridge.cloud.interfaces.resources import Instance, \
 from cloudbridge.cloud.interfaces.resources import Instance, \
-    MachineImageState, NetworkState, RouterState, SnapshotState
+    MachineImageState, NetworkState, RouterState, \
+    SnapshotState, SubnetState
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 
 from msrestazure.azure_exceptions import CloudError
 from msrestazure.azure_exceptions import CloudError
@@ -91,6 +93,7 @@ class AzureSecurityGroup(BaseSecurityGroup):
 
 
     @name.setter
     @name.setter
     def name(self, value):
     def name(self, value):
+        self.assert_valid_resource_name(value)
         self._security_group.tags.update(Name=value)
         self._security_group.tags.update(Name=value)
         self._provider.azure_client. \
         self._provider.azure_client. \
             update_security_group_tags(self.id,
             update_security_group_tags(self.id,
@@ -103,7 +106,7 @@ class AzureSecurityGroup(BaseSecurityGroup):
     @description.setter
     @description.setter
     def description(self, value):
     def description(self, value):
         self._security_group.tags.update(Description=value)
         self._security_group.tags.update(Description=value)
-        self._provider.azure_client. \
+        self._provider.azure_client.\
             update_security_group_tags(self.id,
             update_security_group_tags(self.id,
                                        self._security_group.tags)
                                        self._security_group.tags)
 
 
@@ -121,13 +124,26 @@ class AzureSecurityGroup(BaseSecurityGroup):
 
 
     def delete(self):
     def delete(self):
         try:
         try:
-            self._provider.azure_client. \
+            self._provider.azure_client.\
                 delete_security_group(self.id)
                 delete_security_group(self.id)
             return True
             return True
         except CloudError as cloudError:
         except CloudError as cloudError:
             log.exception(cloudError.message)
             log.exception(cloudError.message)
             return False
             return False
 
 
+    def refresh(self):
+        """
+        Refreshes the security group with tags if required.
+        """
+        try:
+            self._security_group = self._provider.azure_client. \
+                get_security_group(self.id)
+            if not self._security_group.tags:
+                self._security_group.tags = {}
+        except (CloudError, ValueError) as cloudError:
+            log.exception(cloudError.message)
+            # The security group no longer exists and cannot be refreshed.
+
     def add_rule(self, ip_protocol=None, from_port=None, to_port=None,
     def add_rule(self, ip_protocol=None, from_port=None, to_port=None,
                  cidr_ip=None, src_group=None):
                  cidr_ip=None, src_group=None):
         """
         """
@@ -160,7 +176,7 @@ class AzureSecurityGroup(BaseSecurityGroup):
             return self._create_rule(ip_protocol, from_port, to_port, cidr_ip)
             return self._create_rule(ip_protocol, from_port, to_port, cidr_ip)
         elif src_group:
         elif src_group:
             result = None
             result = None
-            sg = (self._provicer.security.security_groups.get(src_group)
+            sg = (self._provider.security.security_groups.get(src_group)
                   if isinstance(src_group, str) else src_group)
                   if isinstance(src_group, str) else src_group)
             for rule in sg.rules:
             for rule in sg.rules:
                 result = self._create_rule(rule.ip_protocol, rule.from_port,
                 result = self._create_rule(rule.ip_protocol, rule.from_port,
@@ -208,9 +224,9 @@ class AzureSecurityGroup(BaseSecurityGroup):
                  cidr_ip=None, src_group=None):
                  cidr_ip=None, src_group=None):
         for rule in self.rules:
         for rule in self.rules:
             if (rule.ip_protocol == ip_protocol and
             if (rule.ip_protocol == ip_protocol and
-                        rule.from_port == str(from_port) and
-                        rule.to_port == str(to_port) and
-                        rule.cidr_ip == cidr_ip):
+                rule.from_port == str(from_port) and
+                rule.to_port == str(to_port) and
+                    rule.cidr_ip == cidr_ip):
                 return rule
                 return rule
         return None
         return None
 
 
@@ -221,7 +237,7 @@ class AzureSecurityGroup(BaseSecurityGroup):
         js['rules'] = [json.loads(r) for r in json_rules]
         js['rules'] = [json.loads(r) for r in json_rules]
         if js.get('network_id'):
         if js.get('network_id'):
             js.pop('network_id')  # Omit for consistency across cloud providers
             js.pop('network_id')  # Omit for consistency across cloud providers
-        return json.dumps(js, sort_keys=True)
+        return js
 
 
 
 
 class AzureSecurityGroupRule(BaseSecurityGroupRule):
 class AzureSecurityGroupRule(BaseSecurityGroupRule):
@@ -370,7 +386,7 @@ class AzureBucketObject(BaseBucketObject):
         Generate a URL to this object.
         Generate a URL to this object.
         """
         """
         return self._provider.azure_client.get_blob_url(
         return self._provider.azure_client.get_blob_url(
-            self._container.name, self.name)
+            self._container.name, self.name, expires_in)
 
 
 
 
 class AzureBucket(BaseBucket):
 class AzureBucket(BaseBucket):
@@ -414,6 +430,11 @@ class AzureBucket(BaseBucket):
         return ClientPagedResultList(self._provider, objects,
         return ClientPagedResultList(self._provider, objects,
                                      limit=limit, marker=marker)
                                      limit=limit, marker=marker)
 
 
+    def find(self, name, limit=None, marker=None):
+        objects = [obj for obj in self if obj.name == name]
+        return ClientPagedResultList(self._provider, objects,
+                                     limit=limit, marker=marker)
+
     def delete(self, delete_contents=True):
     def delete(self, delete_contents=True):
         """
         """
         Delete this bucket.
         Delete this bucket.
@@ -495,6 +516,7 @@ class AzureVolume(BaseVolume):
         Set the volume name.
         Set the volume name.
         """
         """
         # self._volume.name = value
         # self._volume.name = value
+        self.assert_valid_resource_name(value)
         self._volume.tags.update(Name=value)
         self._volume.tags.update(Name=value)
         self._provider.azure_client. \
         self._provider.azure_client. \
             update_disk_tags(self.id,
             update_disk_tags(self.id,
@@ -526,7 +548,7 @@ class AzureVolume(BaseVolume):
     @property
     @property
     def source(self):
     def source(self):
         if self._volume.creation_data.source_uri:
         if self._volume.creation_data.source_uri:
-            url_params = azure_helpers. \
+            url_params = azure_helpers.\
                 parse_url(SNAPSHOT_RESOURCE_ID,
                 parse_url(SNAPSHOT_RESOURCE_ID,
                           self._volume.creation_data.source_uri)
                           self._volume.creation_data.source_uri)
             return self._provider.storage.snapshots. \
             return self._provider.storage.snapshots. \
@@ -682,7 +704,7 @@ class AzureSnapshot(BaseSnapshot):
         """
         """
         Set the snapshot name.
         Set the snapshot name.
         """
         """
-        # self._snapshot.name = value
+        self.assert_valid_resource_name(value)
         self._snapshot.tags.update(Name=value)
         self._snapshot.tags.update(Name=value)
         self._provider.azure_client. \
         self._provider.azure_client. \
             update_snapshot_tags(self.id,
             update_snapshot_tags(self.id,
@@ -705,7 +727,7 @@ class AzureSnapshot(BaseSnapshot):
 
 
     @property
     @property
     def volume_id(self):
     def volume_id(self):
-        url_params = azure_helpers. \
+        url_params = azure_helpers.\
             parse_url(VOLUME_RESOURCE_ID,
             parse_url(VOLUME_RESOURCE_ID,
                       self._snapshot.creation_data.source_resource_id)
                       self._snapshot.creation_data.source_resource_id)
         return url_params.get(VOLUME_NAME)
         return url_params.get(VOLUME_NAME)
@@ -799,6 +821,7 @@ class AzureMachineImage(BaseMachineImage):
         """
         """
         Set the image name.
         Set the image name.
         """
         """
+        self.assert_valid_resource_name(value)
         self._image.tags.update(Name=value)
         self._image.tags.update(Name=value)
         self._provider.azure_client. \
         self._provider.azure_client. \
             update_image_tags(self.id, self._image.tags)
             update_image_tags(self.id, self._image.tags)
@@ -852,7 +875,7 @@ class AzureMachineImage(BaseMachineImage):
         for its latest state.
         for its latest state.
         """
         """
         try:
         try:
-            self._image = self._provider.azure_client \
+            self._image = self._provider.azure_client\
                 .get_image(self.id)
                 .get_image(self.id)
             self._state = self._image.provisioning_state
             self._state = self._image.provisioning_state
         except CloudError as cloudError:
         except CloudError as cloudError:
@@ -897,9 +920,10 @@ class AzureNetwork(BaseNetwork):
         """
         """
         Set the network name.
         Set the network name.
         """
         """
+        self.assert_valid_resource_name(value)
         self._network.tags.update(Name=value)
         self._network.tags.update(Name=value)
         self._provider.azure_client. \
         self._provider.azure_client. \
-            update_network_tags(self.id, self._network.tags)
+            update_network_tags(self.id, self._network)
 
 
     @property
     @property
     def external(self):
     def external(self):
@@ -920,7 +944,7 @@ class AzureNetwork(BaseNetwork):
         for its latest state.
         for its latest state.
         """
         """
         try:
         try:
-            self._network = self._provider.azure_client. \
+            self._network = self._provider.azure_client.\
                 get_network(self.id)
                 get_network(self.id)
             self._state = self._network.provisioning_state
             self._state = self._network.provisioning_state
         except (CloudError, ValueError) as cloudError:
         except (CloudError, ValueError) as cloudError:
@@ -942,19 +966,20 @@ class AzureNetwork(BaseNetwork):
         Delete an existing network.
         Delete an existing network.
         """
         """
         try:
         try:
-            self._provider.azure_client. \
+            self._provider.azure_client.\
                 delete_network(self.id)
                 delete_network(self.id)
             return True
             return True
         except CloudError as cloudError:
         except CloudError as cloudError:
             log.exception(cloudError.message)
             log.exception(cloudError.message)
             return False
             return False
 
 
+    @property
     def subnets(self):
     def subnets(self):
         """
         """
         List all the subnets in this network
         List all the subnets in this network
         :return:
         :return:
         """
         """
-        return self._provider.network.subnets.list(network=self.id)
+        return self._provider.networking.subnets.list(network=self.id)
 
 
     def create_subnet(self, cidr_block, name=None, zone=None):
     def create_subnet(self, cidr_block, name=None, zone=None):
         """
         """
@@ -964,11 +989,12 @@ class AzureNetwork(BaseNetwork):
         :param zone:
         :param zone:
         :return:
         :return:
         """
         """
-        return self._provider.network.subnets. \
+        return self._provider.networking.subnets. \
             create(network=self.id, cidr_block=cidr_block, name=name)
             create(network=self.id, cidr_block=cidr_block, name=name)
 
 
 
 
 class AzureFloatingIP(BaseFloatingIP):
 class AzureFloatingIP(BaseFloatingIP):
+
     def __init__(self, provider, floating_ip):
     def __init__(self, provider, floating_ip):
         super(AzureFloatingIP, self).__init__(provider)
         super(AzureFloatingIP, self).__init__(provider)
         self._ip = floating_ip
         self._ip = floating_ip
@@ -1035,7 +1061,6 @@ class AzurePlacementZone(BasePlacementZone):
     As Azure does not provide zones (limited support), we are mapping the
     As Azure does not provide zones (limited support), we are mapping the
     region information in the zones.
     region information in the zones.
     """
     """
-
     def __init__(self, provider, zone, region):
     def __init__(self, provider, zone, region):
         super(AzurePlacementZone, self).__init__(provider)
         super(AzurePlacementZone, self).__init__(provider)
         self._azure_zone = zone
         self._azure_zone = zone
@@ -1071,12 +1096,18 @@ class AzurePlacementZone(BasePlacementZone):
 
 
 
 
 class AzureSubnet(BaseSubnet):
 class AzureSubnet(BaseSubnet):
+    _SUBNET_STATE_MAP = {
+        'InProgress': SubnetState.PENDING,
+        'Succeeded': SubnetState.AVAILABLE,
+    }
+
     def __init__(self, provider, subnet):
     def __init__(self, provider, subnet):
         super(AzureSubnet, self).__init__(provider)
         super(AzureSubnet, self).__init__(provider)
         self._subnet = subnet
         self._subnet = subnet
-        self._url_params = azure_helpers \
+        self._state = self._subnet.provisioning_state
+        self._url_params = azure_helpers\
             .parse_url(SUBNET_RESOURCE_ID, subnet.id)
             .parse_url(SUBNET_RESOURCE_ID, subnet.id)
-        self._network = self._provider.azure_client. \
+        self._network = self._provider.azure_client.\
             get_network(self._url_params.get(NETWORK_NAME))
             get_network(self._url_params.get(NETWORK_NAME))
 
 
     @property
     @property
@@ -1098,7 +1129,7 @@ class AzureSubnet(BaseSubnet):
 
 
     @property
     @property
     def zone(self):
     def zone(self):
-        region = self._provider. \
+        region = self._provider.\
             compute.regions.get(self._network.location)
             compute.regions.get(self._network.location)
         return region.zones[0]
         return region.zones[0]
 
 
@@ -1124,8 +1155,29 @@ class AzureSubnet(BaseSubnet):
             log.exception(cloudError.message)
             log.exception(cloudError.message)
             return False
             return False
 
 
+    @property
+    def state(self):
+        return self._SUBNET_STATE_MAP.get(
+            self._state, NetworkState.UNKNOWN)
+
+    def refresh(self):
+        """
+        Refreshes the state of this network by re-querying the cloud provider
+        for its latest state.
+        """
+        try:
+            self._network = self._provider.azure_client. \
+                get_network(self.id)
+            self._state = self._network.provisioning_state
+        except (CloudError, ValueError) as cloudError:
+            log.exception(cloudError.message)
+            # The network no longer exists and cannot be refreshed.
+            # set the state to unknown
+            self._state = 'unknown'
+
 
 
 class AzureInstance(BaseInstance):
 class AzureInstance(BaseInstance):
+
     INSTANCE_STATE_MAP = {
     INSTANCE_STATE_MAP = {
         'InProgress': InstanceState.PENDING,
         'InProgress': InstanceState.PENDING,
         'Creating': InstanceState.PENDING,
         'Creating': InstanceState.PENDING,
@@ -1164,7 +1216,7 @@ class AzureInstance(BaseInstance):
         self._public_ip_ids = []
         self._public_ip_ids = []
         self._nic_ids = []
         self._nic_ids = []
         for nic in self._vm.network_profile.network_interfaces:
         for nic in self._vm.network_profile.network_interfaces:
-            nic_params = azure_helpers. \
+            nic_params = azure_helpers.\
                 parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic.id)
                 parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic.id)
             nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
             nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
             self._nic_ids.append(nic_name)
             self._nic_ids.append(nic_name)
@@ -1173,17 +1225,17 @@ class AzureInstance(BaseInstance):
                 sg_params = azure_helpers. \
                 sg_params = azure_helpers. \
                     parse_url(SECURITY_GROUP_RESOURCE_ID,
                     parse_url(SECURITY_GROUP_RESOURCE_ID,
                               nic.network_security_group.id)
                               nic.network_security_group.id)
-                self._security_group_ids. \
+                self._security_group_ids.\
                     append(sg_params.get(SECURITY_GROUP_NAME))
                     append(sg_params.get(SECURITY_GROUP_NAME))
             if nic.ip_configurations:
             if nic.ip_configurations:
                 for ip_config in nic.ip_configurations:
                 for ip_config in nic.ip_configurations:
                     self._private_ips.append(ip_config.private_ip_address)
                     self._private_ips.append(ip_config.private_ip_address)
                     if ip_config.public_ip_address:
                     if ip_config.public_ip_address:
-                        url_params = azure_helpers. \
+                        url_params = azure_helpers.\
                             parse_url(PUBLIC_IP_RESOURCE_ID,
                             parse_url(PUBLIC_IP_RESOURCE_ID,
                                       ip_config.public_ip_address.id)
                                       ip_config.public_ip_address.id)
                         public_ip_name = url_params.get(PUBLIC_IP_NAME)
                         public_ip_name = url_params.get(PUBLIC_IP_NAME)
-                        public_ip = self._provider.azure_client. \
+                        public_ip = self._provider.azure_client.\
                             get_public_ip(public_ip_name)
                             get_public_ip(public_ip_name)
                         self._public_ip_ids.append(public_ip_name)
                         self._public_ip_ids.append(public_ip_name)
                         self._public_ips.append(public_ip.ip_address)
                         self._public_ips.append(public_ip.ip_address)
@@ -1214,9 +1266,10 @@ class AzureInstance(BaseInstance):
         """
         """
         Set the instance name.
         Set the instance name.
         """
         """
+        self.assert_valid_resource_name(value)
         self._vm.tags.update(Name=value)
         self._vm.tags.update(Name=value)
         self._provider.azure_client. \
         self._provider.azure_client. \
-            update_vm_tags(self.id, self._vm.tags)
+            update_vm_tags(self.id, self._vm)
 
 
     @property
     @property
     def public_ips(self):
     def public_ips(self):
@@ -1269,15 +1322,15 @@ class AzureInstance(BaseInstance):
             self._provider.azure_client.delete_public_ip(public_ip_id)
             self._provider.azure_client.delete_public_ip(public_ip_id)
         for data_disk in self._vm.storage_profile.data_disks:
         for data_disk in self._vm.storage_profile.data_disks:
             if data_disk.managed_disk:
             if data_disk.managed_disk:
-                disk_params = azure_helpers. \
+                disk_params = azure_helpers.\
                     parse_url(VOLUME_RESOURCE_ID,
                     parse_url(VOLUME_RESOURCE_ID,
                               data_disk.managed_disk.id)
                               data_disk.managed_disk.id)
-                disk = self._provider.azure_client. \
+                disk = self._provider.azure_client.\
                     get_disk(disk_params.get(VOLUME_NAME))
                     get_disk(disk_params.get(VOLUME_NAME))
                 if disk and disk.tags \
                 if disk and disk.tags \
                         and disk.tags.get('delete_on_terminate',
                         and disk.tags.get('delete_on_terminate',
                                           'False') == 'True':
                                           'False') == 'True':
-                    self._provider.azure_client. \
+                    self._provider.azure_client.\
                         delete_disk(disk_params.get(VOLUME_NAME))
                         delete_disk(disk_params.get(VOLUME_NAME))
         if self._vm.storage_profile.os_disk.managed_disk:
         if self._vm.storage_profile.os_disk.managed_disk:
             disk_params = azure_helpers. \
             disk_params = azure_helpers. \
@@ -1342,6 +1395,8 @@ class AzureInstance(BaseInstance):
         the private key file path
         the private key file path
         """
         """
 
 
+        self.assert_valid_resource_name(name)
+
         if not self._state == 'VM generalized':
         if not self._state == 'VM generalized':
             if not self._state == 'VM running':
             if not self._state == 'VM running':
                 self._provider.azure_client.start_vm(self.id)
                 self._provider.azure_client.start_vm(self.id)
@@ -1360,9 +1415,9 @@ class AzureInstance(BaseInstance):
             },
             },
             'tags': {'Name': name}
             'tags': {'Name': name}
         }
         }
-        self._provider.azure_client. \
+        self._provider.azure_client.\
             create_image(name, create_params)
             create_image(name, create_params)
-        image = self._provider.azure_client. \
+        image = self._provider.azure_client.\
             get_image(name)
             get_image(name)
 
 
         return AzureMachineImage(self._provider, image)
         return AzureMachineImage(self._provider, image)
@@ -1371,7 +1426,7 @@ class AzureInstance(BaseInstance):
         cnopts = pysftp.CnOpts()
         cnopts = pysftp.CnOpts()
         cnopts.hostkeys = None
         cnopts.hostkeys = None
         if private_key_path:
         if private_key_path:
-            with pysftp. \
+            with pysftp.\
                     Connection(self.public_ips[0],
                     Connection(self.public_ips[0],
                                username=self._provider.vm_default_user_name,
                                username=self._provider.vm_default_user_name,
                                cnopts=cnopts,
                                cnopts=cnopts,
@@ -1437,13 +1492,13 @@ class AzureInstance(BaseInstance):
             nic.network_security_group = NetworkSecurityGroup()
             nic.network_security_group = NetworkSecurityGroup()
             nic.network_security_group.id = sg.resource_id
             nic.network_security_group.id = sg.resource_id
         else:
         else:
-            sg_url_params = azure_helpers. \
+            sg_url_params = azure_helpers.\
                 parse_url(SECURITY_GROUP_RESOURCE_ID,
                 parse_url(SECURITY_GROUP_RESOURCE_ID,
                           nic.network_security_group.id)
                           nic.network_security_group.id)
-            existing_sg = self._provider.security. \
+            existing_sg = self._provider.security.\
                 security_groups.get(sg_url_params.get(SECURITY_GROUP_NAME))
                 security_groups.get(sg_url_params.get(SECURITY_GROUP_NAME))
 
 
-            new_sg = self._provider.security.security_groups. \
+            new_sg = self._provider.security.security_groups.\
                 create('{0}-{1}'.format(sg.name, existing_sg.name),
                 create('{0}-{1}'.format(sg.name, existing_sg.name),
                        'Merged security groups {0} and {1}'.
                        'Merged security groups {0} and {1}'.
                        format(sg.name, existing_sg.name))
                        format(sg.name, existing_sg.name))
@@ -1471,7 +1526,7 @@ class AzureInstance(BaseInstance):
         sg = (self._provicer.security.security_groups.get(sg)
         sg = (self._provicer.security.security_groups.get(sg)
               if isinstance(sg, str) else sg)
               if isinstance(sg, str) else sg)
         if nic.network_security_group and \
         if nic.network_security_group and \
-                        nic.network_security_group.id == sg.resource_id:
+                nic.network_security_group.id == sg.resource_id:
             nic.network_security_group = None
             nic.network_security_group = None
             self._provider.azure_client.create_nic(self._nic_ids[0], nic)
             self._provider.azure_client.create_nic(self._nic_ids[0], nic)
 
 
@@ -1517,22 +1572,24 @@ class AzureInstance(BaseInstance):
 
 
 
 
 class AzureLaunchConfig(BaseLaunchConfig):
 class AzureLaunchConfig(BaseLaunchConfig):
+
     def __init__(self, provider):
     def __init__(self, provider):
         super(AzureLaunchConfig, self).__init__(provider)
         super(AzureLaunchConfig, self).__init__(provider)
 
 
 
 
-class AzureInstanceType(BaseInstanceType):
-    def __init__(self, provider, instance_type):
-        super(AzureInstanceType, self).__init__(provider)
-        self._inst_type = instance_type
+class AzureVMType(BaseVMType):
+
+    def __init__(self, provider, vm_type):
+        super(AzureVMType, self).__init__(provider)
+        self._vm_type = vm_type
 
 
     @property
     @property
     def id(self):
     def id(self):
-        return self._inst_type.name
+        return self._vm_type.name
 
 
     @property
     @property
     def name(self):
     def name(self):
-        return self._inst_type.name
+        return self._vm_type.name
 
 
     @property
     @property
     def family(self):
     def family(self):
@@ -1544,19 +1601,19 @@ class AzureInstanceType(BaseInstanceType):
 
 
     @property
     @property
     def vcpus(self):
     def vcpus(self):
-        return self._inst_type.number_of_cores
+        return self._vm_type.number_of_cores
 
 
     @property
     @property
     def ram(self):
     def ram(self):
-        return self._inst_type.memory_in_mb
+        return self._vm_type.memory_in_mb
 
 
     @property
     @property
     def size_root_disk(self):
     def size_root_disk(self):
-        return self._inst_type.os_disk_size_in_mb / 1024
+        return self._vm_type.os_disk_size_in_mb / 1024
 
 
     @property
     @property
     def size_ephemeral_disks(self):
     def size_ephemeral_disks(self):
-        return self._inst_type.resource_disk_size_in_mb / 1024
+        return self._vm_type.resource_disk_size_in_mb / 1024
 
 
     @property
     @property
     def num_ephemeral_disks(self):
     def num_ephemeral_disks(self):
@@ -1570,12 +1627,13 @@ class AzureInstanceType(BaseInstanceType):
     @property
     @property
     def extra_data(self):
     def extra_data(self):
         return {
         return {
-            'max_data_disk_count':
-                self._inst_type.max_data_disk_count
-        }
+                    'max_data_disk_count':
+                    self._vm_type.max_data_disk_count
+               }
 
 
 
 
 class AzureKeyPair(BaseKeyPair):
 class AzureKeyPair(BaseKeyPair):
+
     def __init__(self, provider, key_pair):
     def __init__(self, provider, key_pair):
         super(AzureKeyPair, self).__init__(provider, key_pair)
         super(AzureKeyPair, self).__init__(provider, key_pair)
         self._material = None
         self._material = None
@@ -1605,7 +1663,7 @@ class AzureKeyPair(BaseKeyPair):
 
 
     def delete(self):
     def delete(self):
         try:
         try:
-            self._provider.azure_client. \
+            self._provider.azure_client.\
                 delete_public_key(self._key_pair)
                 delete_public_key(self._key_pair)
             return True
             return True
         except CloudError:
         except CloudError:
@@ -1613,24 +1671,19 @@ class AzureKeyPair(BaseKeyPair):
 
 
 
 
 class AzureRouter(BaseRouter):
 class AzureRouter(BaseRouter):
-    def __init__(self, provider, router):
+    def __init__(self, provider, route_table):
         super(AzureRouter, self).__init__(provider)
         super(AzureRouter, self).__init__(provider)
-        self._router = router
-        self._ROUTE_CIDR = '0.0.0.0/0'
-        self._name = None
-        self._network_id = None
-        self._state = RouterState.DETACHED
-
-    def _route_table(self, subnet_id):
-        pass
+        self._route_table = route_table
+        if not self._route_table.tags:
+            self._route_table.tags = {}
 
 
     @property
     @property
     def id(self):
     def id(self):
-        return self._name
+        return self._route_table.name
 
 
     @property
     @property
     def resource_id(self):
     def resource_id(self):
-        pass
+        return self._route_table.id
 
 
     @property
     @property
     def name(self):
     def name(self):
@@ -1639,7 +1692,7 @@ class AzureRouter(BaseRouter):
 
 
         .. note:: the router must have a (case sensitive) tag ``Name``
         .. note:: the router must have a (case sensitive) tag ``Name``
         """
         """
-        return self._name
+        return self._route_table.tags.get('Name', self._route_table.name)
 
 
     @name.setter
     @name.setter
     # pylint:disable=arguments-differ
     # pylint:disable=arguments-differ
@@ -1647,47 +1700,98 @@ class AzureRouter(BaseRouter):
         """
         """
         Set the router name.
         Set the router name.
         """
         """
-        self._name = value
+        self.assert_valid_resource_name(value)
+        self._route_table.tags.update(Name=value)
+        self._provider.azure_client. \
+            update_route_table_tags(self._route_table.name,
+                                    self._route_table)
 
 
     def refresh(self):
     def refresh(self):
-        pass
+        self._route_table = self._provider.azure_client. \
+            get_route_table(self._route_table.name)
 
 
     @property
     @property
     def state(self):
     def state(self):
-        return self._state
+        self.refresh()  # Explicitly refresh the local object
+        if self._route_table.subnets:
+            return RouterState.ATTACHED
+        return RouterState.DETACHED
 
 
     @property
     @property
     def network_id(self):
     def network_id(self):
-        return self._network_id
+        return None
 
 
     def delete(self):
     def delete(self):
-        pass
+        self._provider.azure_client. \
+            delete_route_table(self.name)
 
 
-    def attach_network(self, network_id):
-        self._network_id = network_id
-        self._state = RouterState.ATTACHED
+    def attach_subnet(self, subnet):
+        subnet_id_parts = subnet.id.split('|$|')
+        if (len(subnet_id_parts) != 2):
+            pass
+        self._provider.azure_client. \
+            attach_subnet_to_route_table(subnet_id_parts[0],
+                                         subnet_id_parts[1],
+                                         self.resource_id)
+        self.refresh()
+
+    def detach_subnet(self, subnet):
+        subnet_id_parts = subnet.id.split('|$|')
+        if (len(subnet_id_parts) != 2):
+            pass
+        self._provider.azure_client. \
+            detach_subnet_to_route_table(subnet_id_parts[0],
+                                         subnet_id_parts[1],
+                                         self.resource_id)
+        self.refresh()
 
 
-    def detach_network(self):
+    def attach_gateway(self, gateway):
         pass
         pass
 
 
-    def add_route(self, subnet_id):
-        """
-        Add a default route to this router.
+    def detach_gateway(self, gateway):
+        pass
 
 
-        For Azure, routes are added to a route table. A route table is assoc.
-        with a network vs. a subnet so we retrieve the network via the subnet.
-        Note that the subnet must belong to the same network as the router
-        is attached to.
 
 
-        Further, only a single route can be added, targeting the Internet
-        (i.e., destination CIDR block ``0.0.0.0/0``).
+class AzureInternetGateway(BaseInternetGateway):
+    def __init__(self, provider, gateway):
+        super(AzureInternetGateway, self).__init__(provider)
+        self._gateway = gateway
+        self._name = None
+        self._network_id = None
+        self._state = ''
+
+    @property
+    def id(self):
+        return self._name
+
+    @property
+    def name(self):
         """
         """
-        pass
+        Get the gateway name.
 
 
-    def remove_route(self, subnet_id):
+        .. note:: the gateway must have a (case sensitive) tag ``Name``
         """
         """
-        Remove the default Internet route from this router.
+        return self._name
 
 
-        .. seealso:: ``add_route`` method
+    @name.setter
+    # pylint:disable=arguments-differ
+    def name(self, value):
+        """
+        Set the router name.
         """
         """
+        self.assert_valid_resource_name(value)
+        self._name = value
+
+    def refresh(self):
+        pass
+
+    @property
+    def state(self):
+        return self._state
+
+    @property
+    def network_id(self):
+        return None
+
+    def delete(self):
         pass
         pass

+ 18 - 20
cloudbridge/cloud/providers/azure/services.py

@@ -7,25 +7,23 @@ from azure.common import AzureException
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBucketService, \
 from cloudbridge.cloud.base.services import BaseBucketService, \
     BaseComputeService, BaseGatewayService, BaseImageService, \
     BaseComputeService, BaseGatewayService, BaseImageService, \
-    BaseInstanceService, BaseInstanceTypesService, \
-    BaseKeyPairService, BaseNetworkService, BaseNetworkingService, \
-    BaseRegionService, BaseRouterService, BaseSecurityGroupService, \
-    BaseSecurityService, BaseSnapshotService, BaseStorageService, \
-    BaseSubnetService, BaseVolumeService
+    BaseInstanceService, BaseKeyPairService, BaseNetworkService, \
+    BaseNetworkingService, BaseRegionService, BaseRouterService, \
+    BaseSecurityGroupService, BaseSecurityService, BaseSnapshotService, \
+    BaseStorageService, BaseSubnetService, BaseVMTypeService, BaseVolumeService
 from cloudbridge.cloud.interfaces import InvalidConfigurationException
 from cloudbridge.cloud.interfaces import InvalidConfigurationException
-from cloudbridge.cloud.interfaces.resources import InstanceType, \
-    MachineImage, Network, PlacementZone, SecurityGroup, \
-    Snapshot, Subnet, Volume
+from cloudbridge.cloud.interfaces.resources import MachineImage, \
+    Network, PlacementZone, SecurityGroup, Snapshot, Subnet, \
+    VMType, Volume
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 
 from msrestazure.azure_exceptions import CloudError
 from msrestazure.azure_exceptions import CloudError
 
 
 from .resources import AzureBucket, AzureFloatingIP, \
 from .resources import AzureBucket, AzureFloatingIP, \
-    AzureInstance, AzureInstanceType, \
-    AzureInternetGateway, AzureKeyPair, \
-    AzureLaunchConfig, AzureMachineImage, \
-    AzureNetwork, AzureRegion, AzureRouter, AzureSecurityGroup, \
-    AzureSnapshot, AzureSubnet, AzureVolume
+    AzureInstance, AzureInternetGateway, AzureKeyPair, \
+    AzureLaunchConfig, AzureMachineImage, AzureNetwork, \
+    AzureRegion, AzureRouter, AzureSecurityGroup, AzureSnapshot, \
+    AzureSubnet, AzureVMType, AzureVolume
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
 
 
@@ -426,7 +424,7 @@ class AzureSnapshotService(BaseSnapshotService):
 class AzureComputeService(BaseComputeService):
 class AzureComputeService(BaseComputeService):
     def __init__(self, provider):
     def __init__(self, provider):
         super(AzureComputeService, self).__init__(provider)
         super(AzureComputeService, self).__init__(provider)
-        self._instance_type_svc = AzureInstanceTypesService(self.provider)
+        self._instance_type_svc = AzureVMTypeService(self.provider)
         self._instance_svc = AzureInstanceService(self.provider)
         self._instance_svc = AzureInstanceService(self.provider)
         self._region_svc = AzureRegionService(self.provider)
         self._region_svc = AzureRegionService(self.provider)
         self._images_svc = AzureImageService(self.provider)
         self._images_svc = AzureImageService(self.provider)
@@ -473,7 +471,7 @@ class AzureInstanceService(BaseInstanceService):
                  if isinstance(image, str) else image)
                  if isinstance(image, str) else image)
 
 
         instance_size = instance_type.id if \
         instance_size = instance_type.id if \
-            isinstance(instance_type, InstanceType) else instance_type
+            isinstance(instance_type, VMType) else instance_type
 
 
         if not subnet:
         if not subnet:
             subnet = self.provider.networking.subnets.get_or_create_default()
             subnet = self.provider.networking.subnets.get_or_create_default()
@@ -775,10 +773,10 @@ class AzureImageService(BaseImageService):
                                      limit=limit, marker=marker)
                                      limit=limit, marker=marker)
 
 
 
 
-class AzureInstanceTypesService(BaseInstanceTypesService):
+class AzureVMTypeService(BaseVMTypeService):
 
 
     def __init__(self, provider):
     def __init__(self, provider):
-        super(AzureInstanceTypesService, self).__init__(provider)
+        super(AzureVMTypeService, self).__init__(provider)
 
 
     @property
     @property
     def instance_data(self):
     def instance_data(self):
@@ -789,9 +787,9 @@ class AzureInstanceTypesService(BaseInstanceTypesService):
         return r
         return r
 
 
     def list(self, limit=None, marker=None):
     def list(self, limit=None, marker=None):
-        inst_types = [AzureInstanceType(self.provider, inst_type)
-                      for inst_type in self.instance_data]
-        return ClientPagedResultList(self.provider, inst_types,
+        vm_types = [AzureVMType(self.provider, vm_type)
+                    for vm_type in self.instance_data]
+        return ClientPagedResultList(self.provider, vm_types,
                                      limit=limit, marker=marker)
                                      limit=limit, marker=marker)