Jelajahi Sumber

Merge pull request #152 from CloudVE/azure-patch

Azure patch
Enis Afgan 7 tahun lalu
induk
melakukan
ce187c54e3

+ 34 - 0
cloudbridge/cloud/base/helpers.py

@@ -1,4 +1,5 @@
 import fnmatch
+import functools
 import os
 import re
 import sys
@@ -9,8 +10,12 @@ from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import serialization as crypt_serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
 
+from deprecation import deprecated
+
 import six
 
+import cloudbridge
+
 
 def generate_key_pair():
     """
@@ -129,3 +134,32 @@ def get_env(varname, default_value=None):
             value, six.text_type):
         return six.u(value)
     return value
+
+
+# Alias deprication decorator, following:
+# https://stackoverflow.com/questions/49802412/
+# how-to-implement-deprecation-in-python-with-argument-alias
+def deprecated_alias(**aliases):
+    def deco(f):
+        @functools.wraps(f)
+        def wrapper(*args, **kwargs):
+            rename_kwargs(f.__name__, kwargs, aliases)
+            return f(*args, **kwargs)
+        return wrapper
+    return deco
+
+
+def rename_kwargs(func_name, kwargs, aliases):
+    for alias, new in aliases.items():
+        if alias in kwargs:
+            if new in kwargs:
+                raise TypeError('{} received both {} and {}'.format(
+                    func_name, alias, new))
+            # Manually invoke the deprecated decorator with an empty lambda
+            # to signal deprecation
+            deprecated(deprecated_in='1.1',
+                       removed_in='2.0',
+                       current_version=cloudbridge.__version__,
+                       details='{} is deprecated, use {} instead'.format(
+                           alias, new))(lambda: None)()
+            kwargs[new] = kwargs.pop(alias)

+ 2 - 2
cloudbridge/cloud/providers/aws/provider.py

@@ -105,9 +105,9 @@ class AWSCloudProvider(BaseCloudProvider):
         """
         Get a boto ec2 connection object.
         """
-        return self._conect_ec2_region(region_name=self.region_name)
+        return self._connect_ec2_region(region_name=self.region_name)
 
-    def _conect_ec2_region(self, region_name=None):
+    def _connect_ec2_region(self, region_name=None):
         '''Get an EC2 resource object'''
         return self.session.resource(
             'ec2', region_name=region_name, **self.ec2_cfg)

+ 1 - 1
cloudbridge/cloud/providers/aws/resources.py

@@ -952,7 +952,7 @@ class AWSRegion(BaseRegion):
             conn = self._provider.ec2_conn
         else:
             # pylint:disable=protected-access
-            conn = self._provider._conect_ec2_region(region_name=self.id)
+            conn = self._provider._connect_ec2_region(region_name=self.id)
 
         zones = (conn.meta.client.describe_availability_zones()
                  .get('AvailabilityZones', []))

+ 5 - 2
cloudbridge/cloud/providers/aws/services.py

@@ -30,6 +30,7 @@ from cloudbridge.cloud.interfaces.exceptions \
     import DuplicateResourceException, InvalidConfigurationException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import MachineImage
+from cloudbridge.cloud.interfaces.resources import Network
 from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import VMFirewall
@@ -134,12 +135,14 @@ class AWSVMFirewallService(BaseVMFirewallService):
     def list(self, limit=None, marker=None):
         return self.svc.list(limit=limit, marker=marker)
 
-    def create(self, label, network_id, description=None):
+    @cb_helpers.deprecated_alias(network_id='network')
+    def create(self, label, network=None, description=None):
         log.debug("Creating Firewall Service with the parameters "
-                  "[label: %s id: %s description: %s]", label, network_id,
+                  "[label: %s id: %s description: %s]", label, network,
                   description)
         AWSVMFirewall.assert_valid_resource_label(label)
         name = AWSVMFirewall._generate_name_from_label(label, 'cb-fw')
+        network_id = network.id if isinstance(network, Network) else network
         obj = self.svc.create('create_security_group', GroupName=name,
                               Description=description or name,
                               VpcId=network_id)

+ 5 - 2
cloudbridge/cloud/providers/azure/azure_client.py

@@ -408,8 +408,11 @@ class AzureClient(object):
         return self.network_management_client.security_rules. \
             delete(self.resource_group, vm_firewall, name).result()
 
-    def list_containers(self, prefix=None):
-        return self.blob_service.list_containers(prefix=prefix)
+    def list_containers(self, prefix=None, limit=None, marker=None):
+        results = self.blob_service.list_containers(prefix=prefix,
+                                                    num_results=limit,
+                                                    marker=marker)
+        return (results.items, results.next_marker)
 
     def create_container(self, container_name):
         try:

+ 23 - 2
cloudbridge/cloud/providers/azure/provider.py

@@ -1,10 +1,13 @@
 import logging
 import uuid
 
+from deprecation import deprecated
+
 from msrestazure.azure_exceptions import CloudError
 
 import tenacity
 
+import cloudbridge
 from cloudbridge.cloud.base import BaseCloudProvider
 from cloudbridge.cloud.base.helpers import get_env
 from cloudbridge.cloud.interfaces.exceptions import ProviderConnectionException
@@ -54,8 +57,9 @@ class AzureCloudProvider(BaseCloudProvider):
                                str(self.resource_group)))[-6:]))
 
         self.vm_default_user_name = self._get_config_value(
-            'azure_vm_default_user_name', get_env(
-                'AZURE_VM_DEFAULT_USER_NAME', 'cbuser'))
+                'azure_vm_default_username', get_env(
+                    'AZURE_VM_DEFAULT_USERNAME', None)) \
+            or self.__get_deprecated_username('cbuser')
 
         self.public_key_storage_table_name = self._get_config_value(
             'azure_public_key_storage_table_name', get_env(
@@ -68,6 +72,23 @@ class AzureCloudProvider(BaseCloudProvider):
         self._compute = AzureComputeService(self)
         self._networking = AzureNetworkingService(self)
 
+    def __get_deprecated_username(self, default):
+        username = self._get_config_value(
+            'azure_vm_default_user_name', get_env(
+                'AZURE_VM_DEFAULT_USER_NAME', None))
+        if username:
+            return self.__wrap_deprecated_username(username)
+        else:
+            return default
+
+    @deprecated(deprecated_in='1.1',
+                removed_in='2.0',
+                current_version=cloudbridge.__version__,
+                details='AZURE_VM_DEFAULT_USER_NAME was deprecated in favor '
+                        'of AZURE_VM_DEFAULT_USERNAME')
+    def __wrap_deprecated_username(self, username):
+        return username
+
     @property
     def compute(self):
         return self._compute

+ 19 - 5
cloudbridge/cloud/providers/azure/services.py

@@ -66,7 +66,8 @@ class AzureVMFirewallService(BaseVMFirewallService):
                for fw in self.provider.azure_client.list_vm_firewall()]
         return ClientPagedResultList(self.provider, fws, limit, marker)
 
-    def create(self, label, description=None, network_id=None):
+    @cb_helpers.deprecated_alias(network_id='network')
+    def create(self, label, network=None, description=None):
         AzureVMFirewall.assert_valid_resource_label(label)
         name = AzureVMFirewall._generate_name_from_label(label, "cb-fw")
         parameters = {"location": self.provider.region_name,
@@ -227,10 +228,15 @@ class AzureBucketService(BaseBucketService):
         """
         List all containers.
         """
-        buckets = [AzureBucket(self.provider, bucket)
-                   for bucket in self.provider.azure_client.list_containers()]
-        return ClientPagedResultList(self.provider, buckets,
-                                     limit=limit, marker=marker)
+        buckets, resume_marker = self.provider.azure_client.list_containers(
+            limit=limit or self.provider.config.default_result_limit,
+            marker=marker)
+        results = [AzureBucket(self.provider, bucket)
+                   for bucket in buckets]
+        return ServerPagedResultList(is_truncated=resume_marker,
+                                     marker=resume_marker,
+                                     supports_total=False,
+                                     data=results)
 
     def create(self, name, location=None):
         """
@@ -1037,6 +1043,14 @@ class AzureSubnetService(BaseSubnetService):
     def delete(self, subnet):
         subnet_id = subnet.id if isinstance(subnet, Subnet) else subnet
         self.provider.azure_client.delete_subnet(subnet_id)
+        # Although Subnet doesn't support labels, we use the parent Network's
+        # tags to track the subnet's labels, thus that network-level tag must
+        # be deleted with the subnet
+        network = subnet._network
+        az_network = network._network
+        az_network.tags.pop(subnet.tag_name)
+        self._provider.azure_client.update_network_tags(
+            az_network.id, az_network)
 
 
 class AzureRouterService(BaseRouterService):

+ 3 - 6
cloudbridge/cloud/providers/openstack/resources.py

@@ -453,12 +453,10 @@ class OpenStackInstance(BaseInstance):
         """
         log.debug("Creating OpenStack Image with the label %s", label)
         self.assert_valid_resource_label(label)
-        name = self._generate_name_from_label(label, 'cb-img')
 
-        image_id = self._os_instance.create_image(name)
+        image_id = self._os_instance.create_image(label)
         img = OpenStackMachineImage(
             self._provider, self._provider.compute.images.get(image_id))
-        img.label = label
         return img
 
     def _get_fip(self, floating_ip):
@@ -785,13 +783,12 @@ class OpenStackSnapshot(BaseSnapshot):
         Create a new Volume from this Snapshot.
         """
         vol_label = "from-snap-{0}".format(self.id or self.label)
-        name = self._generate_name_from_label(vol_label, 'cb-vol')
+        self.assert_valid_resource_label(vol_label)
         size = size if size else self._snapshot.size
         os_vol = self._provider.cinder.volumes.create(
-            size, name=name, availability_zone=placement,
+            size, name=vol_label, availability_zone=placement,
             snapshot_id=self._snapshot.id)
         cb_vol = OpenStackVolume(self._provider, os_vol)
-        cb_vol.label = vol_label
         return cb_vol
 
 

+ 5 - 7
cloudbridge/cloud/providers/openstack/services.py

@@ -210,14 +210,14 @@ class OpenStackVMFirewallService(BaseVMFirewallService):
         return ClientPagedResultList(self.provider, firewalls,
                                      limit=limit, marker=marker)
 
-    def create(self, label, description, network_id):
+    @cb_helpers.deprecated_alias(network_id='network')
+    def create(self, label, network, description=None):
         OpenStackVMFirewall.assert_valid_resource_label(label)
-        name = OpenStackVMFirewall._generate_name_from_label(label, 'cb-fw')
         log.debug("Creating OpenStack VM Firewall with the params: "
                   "[label: %s network id: %s description: %s]", label,
-                  network_id, description)
+                  network, description)
         sg = self.provider.os_conn.network.create_security_group(
-            name=name, description=description or name)
+            name=label, description=description or label)
         if sg:
             return OpenStackVMFirewall(self.provider, sg)
         return None
@@ -858,15 +858,13 @@ class OpenStackSubnetService(BaseSubnetService):
                   "[Label: %s Network: %s Cinder Block: %s Zone: -ignored-]",
                   label, network, cidr_block)
         OpenStackSubnet.assert_valid_resource_label(label)
-        name = OpenStackSubnet._generate_name_from_label(label, 'cb-subnet')
         network_id = (network.id if isinstance(network, OpenStackNetwork)
                       else network)
-        subnet_info = {'name': name, 'network_id': network_id,
+        subnet_info = {'name': label, 'network_id': network_id,
                        'cidr': cidr_block, 'ip_version': 4}
         subnet = (self.provider.neutron.create_subnet({'subnet': subnet_info})
                   .get('subnet'))
         cb_subnet = OpenStackSubnet(self.provider, subnet)
-        cb_subnet.label = label
         return cb_subnet
 
     def get_or_create_default(self, zone):

+ 2 - 1
setup.py

@@ -22,7 +22,8 @@ REQS_BASE = [
     'bunch>=1.0.1',
     'six>=1.11',
     'tenacity>=4.12.0,<=5.0',
-    'cachetools>=2.1.0'
+    'cachetools>=2.1.0',
+    'deprecated>=1.2.3'
 ]
 REQS_AWS = ['boto3<1.8.0']
 # Install azure>=3.0.0 package to find which of the azure libraries listed