mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
modified storageaccount fact return curated result with connection string (#49702)
This commit is contained in:
parent
896e320142
commit
664e6fb9c8
8 changed files with 521 additions and 66 deletions
|
@ -205,7 +205,7 @@ def normalize_location_name(name):
|
|||
AZURE_PKG_VERSIONS = {
|
||||
'StorageManagementClient': {
|
||||
'package_name': 'storage',
|
||||
'expected_version': '1.5.0'
|
||||
'expected_version': '3.1.0'
|
||||
},
|
||||
'ComputeManagementClient': {
|
||||
'package_name': 'compute',
|
||||
|
@ -379,6 +379,7 @@ class AzureRMModuleBase(object):
|
|||
:param tags: metadata tags from the object
|
||||
:return: bool, dict
|
||||
'''
|
||||
tags = tags or dict()
|
||||
new_tags = copy.copy(tags) if isinstance(tags, dict) else dict()
|
||||
param_tags = self.module.params.get('tags') if isinstance(self.module.params.get('tags'), dict) else dict()
|
||||
append_tags = self.module.params.get('append_tags') if self.module.params.get('append_tags') is not None else True
|
||||
|
@ -790,12 +791,12 @@ class AzureRMModuleBase(object):
|
|||
if not self._storage_client:
|
||||
self._storage_client = self.get_mgmt_svc_client(StorageManagementClient,
|
||||
base_url=self._cloud_environment.endpoints.resource_manager,
|
||||
api_version='2017-10-01')
|
||||
api_version='2018-07-01')
|
||||
return self._storage_client
|
||||
|
||||
@property
|
||||
def storage_models(self):
|
||||
return StorageManagementClient.models("2017-10-01")
|
||||
return StorageManagementClient.models("2018-07-01")
|
||||
|
||||
@property
|
||||
def network_client(self):
|
||||
|
|
|
@ -54,6 +54,7 @@ options:
|
|||
- StandardSSD_LRS
|
||||
- Standard_RAGRS
|
||||
- Standard_ZRS
|
||||
- Premium_ZRS
|
||||
aliases:
|
||||
- type
|
||||
custom_domain:
|
||||
|
@ -62,6 +63,8 @@ options:
|
|||
keys where 'name' is the CNAME source. Only one custom domain is supported per storage account at this
|
||||
time. To clear the existing custom domain, use an empty string for the custom domain name property.
|
||||
- Can be added to an existing storage account. Will be ignored during storage account creation.
|
||||
aliases:
|
||||
- custom_dns_domain_suffix
|
||||
kind:
|
||||
description:
|
||||
- The 'kind' of storage.
|
||||
|
@ -78,10 +81,51 @@ options:
|
|||
- Hot
|
||||
- Cool
|
||||
version_added: "2.4"
|
||||
force:
|
||||
force_delete_nonempty:
|
||||
description:
|
||||
- Attempt deletion if resource already exists and cannot be updated
|
||||
type: bool
|
||||
aliases:
|
||||
- force
|
||||
https_only:
|
||||
description:
|
||||
- Allows https traffic only to storage service if sets to true.
|
||||
type: bool
|
||||
version_added: "2.8"
|
||||
blob_cors:
|
||||
description:
|
||||
- Specifies CORS rules for the Blob service.
|
||||
- You can include up to five CorsRule elements in the request.
|
||||
- If no blob_cors elements are included in the argument list, nothing about CORS will be changed.
|
||||
- "If you want to delete all CORS rules and disable CORS for the Blob service, explicitly set blob_cors: []."
|
||||
type: list
|
||||
version_added: "2.8"
|
||||
suboptions:
|
||||
allowed_origins:
|
||||
description:
|
||||
- A list of origin domains that will be allowed via CORS, or "*" to allow all domains.
|
||||
type: list
|
||||
required: true
|
||||
allowed_methods:
|
||||
description:
|
||||
- A list of HTTP methods that are allowed to be executed by the origin.
|
||||
type: list
|
||||
required: true
|
||||
max_age_in_seconds:
|
||||
description:
|
||||
- The number of seconds that the client/browser should cache a preflight response.
|
||||
type: int
|
||||
required: true
|
||||
exposed_headers:
|
||||
description:
|
||||
- A list of response headers to expose to CORS clients.
|
||||
type: list
|
||||
required: true
|
||||
allowed_headers:
|
||||
description:
|
||||
- A list of headers allowed to be part of the cross-origin request.
|
||||
type: list
|
||||
required: true
|
||||
|
||||
extends_documentation_fragment:
|
||||
- azure
|
||||
|
@ -90,7 +134,6 @@ extends_documentation_fragment:
|
|||
author:
|
||||
- "Chris Houseknecht (@chouseknecht)"
|
||||
- "Matt Davis (@nitzmahone)"
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
@ -108,6 +151,25 @@ EXAMPLES = '''
|
|||
tags:
|
||||
testing: testing
|
||||
delete: on-exit
|
||||
|
||||
- name: create an account with blob CORS
|
||||
azure_rm_storageaccount:
|
||||
resource_group: Testing
|
||||
name: clh002
|
||||
type: Standard_RAGRS
|
||||
blob_cors:
|
||||
- allowed_origins:
|
||||
- http://www.example.com/
|
||||
allowed_methods:
|
||||
- GET
|
||||
- POST
|
||||
allowed_headers:
|
||||
- x-ms-meta-data*
|
||||
- x-ms-meta-target*
|
||||
- x-ms-meta-abc
|
||||
exposed_headers:
|
||||
- x-ms-meta-*
|
||||
max_age_in_seconds: 200
|
||||
'''
|
||||
|
||||
|
||||
|
@ -151,7 +213,36 @@ except ImportError:
|
|||
# This is handled in azure_rm_common
|
||||
pass
|
||||
|
||||
from ansible.module_utils.azure_rm_common import AZURE_SUCCESS_STATE, AzureRMModuleBase, HAS_AZURE
|
||||
import copy
|
||||
from ansible.module_utils.azure_rm_common import AZURE_SUCCESS_STATE, AzureRMModuleBase
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
cors_rule_spec = dict(
|
||||
allowed_origins=dict(type='list', elements='str', required=True),
|
||||
allowed_methods=dict(type='list', elements='str', required=True),
|
||||
max_age_in_seconds=dict(type='int', required=True),
|
||||
exposed_headers=dict(type='list', elements='str', required=True),
|
||||
allowed_headers=dict(type='list', elements='str', required=True),
|
||||
)
|
||||
|
||||
|
||||
def compare_cors(cors1, cors2):
|
||||
if len(cors1) != len(cors2):
|
||||
return False
|
||||
copy2 = copy.copy(cors2)
|
||||
for rule1 in cors1:
|
||||
matched = False
|
||||
for rule2 in copy2:
|
||||
if (rule1['max_age_in_seconds'] == rule2['max_age_in_seconds']
|
||||
and set(rule1['allowed_methods']) == set(rule2['allowed_methods'])
|
||||
and set(rule1['allowed_origins']) == set(rule2['allowed_origins'])
|
||||
and set(rule1['allowed_headers']) == set(rule2['allowed_headers'])
|
||||
and set(rule1['exposed_headers']) == set(rule2['exposed_headers'])):
|
||||
matched = True
|
||||
copy2.remove(rule2)
|
||||
if not matched:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class AzureRMStorageAccount(AzureRMModuleBase):
|
||||
|
@ -159,24 +250,22 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
def __init__(self):
|
||||
|
||||
self.module_arg_spec = dict(
|
||||
account_type=dict(type='str', choices=['Premium_LRS', 'Standard_GRS', 'Standard_LRS', 'StandardSSD_LRS', 'Standard_RAGRS', 'Standard_ZRS'],
|
||||
account_type=dict(type='str',
|
||||
choices=['Premium_LRS', 'Standard_GRS', 'Standard_LRS', 'StandardSSD_LRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_ZRS'],
|
||||
aliases=['type']),
|
||||
custom_domain=dict(type='dict'),
|
||||
custom_domain=dict(type='dict', aliases=['custom_dns_domain_suffix']),
|
||||
location=dict(type='str'),
|
||||
name=dict(type='str', required=True),
|
||||
resource_group=dict(required=True, type='str', aliases=['resource_group_name']),
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
force=dict(type='bool', default=False),
|
||||
force_delete_nonempty=dict(type='bool', default=False, aliases=['force']),
|
||||
tags=dict(type='dict'),
|
||||
kind=dict(type='str', default='Storage', choices=['Storage', 'StorageV2', 'BlobStorage']),
|
||||
access_tier=dict(type='str', choices=['Hot', 'Cool'])
|
||||
access_tier=dict(type='str', choices=['Hot', 'Cool']),
|
||||
https_only=dict(type='bool', default=False),
|
||||
blob_cors=dict(type='list', options=cors_rule_spec, elements='dict')
|
||||
)
|
||||
|
||||
if HAS_AZURE:
|
||||
for key in self.storage_models.SkuName:
|
||||
if getattr(key, 'value') not in self.module_arg_spec['account_type']['choices']:
|
||||
self.module_arg_spec['account_type']['choices'].append(getattr(key, 'value'))
|
||||
|
||||
self.results = dict(
|
||||
changed=False,
|
||||
state=dict()
|
||||
|
@ -190,9 +279,11 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
self.account_type = None
|
||||
self.custom_domain = None
|
||||
self.tags = None
|
||||
self.force = None
|
||||
self.force_delete_nonempty = None
|
||||
self.kind = None
|
||||
self.access_tier = None
|
||||
self.https_only = None
|
||||
self.blob_cors = None
|
||||
|
||||
super(AzureRMStorageAccount, self).__init__(self.module_arg_spec,
|
||||
supports_check_mode=True)
|
||||
|
@ -254,19 +345,21 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
def get_account(self):
|
||||
self.log('Get properties for account {0}'.format(self.name))
|
||||
account_obj = None
|
||||
blob_service_props = None
|
||||
account_dict = None
|
||||
|
||||
try:
|
||||
account_obj = self.storage_client.storage_accounts.get_properties(self.resource_group, self.name)
|
||||
blob_service_props = self.storage_client.blob_services.get_service_properties(self.resource_group, self.name)
|
||||
except CloudError:
|
||||
pass
|
||||
|
||||
if account_obj:
|
||||
account_dict = self.account_obj_to_dict(account_obj)
|
||||
account_dict = self.account_obj_to_dict(account_obj, blob_service_props)
|
||||
|
||||
return account_dict
|
||||
|
||||
def account_obj_to_dict(self, account_obj):
|
||||
def account_obj_to_dict(self, account_obj, blob_service_props=None):
|
||||
account_dict = dict(
|
||||
id=account_obj.id,
|
||||
name=account_obj.name,
|
||||
|
@ -283,7 +376,8 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
if account_obj.status_of_primary is not None else None),
|
||||
status_of_secondary=(account_obj.status_of_secondary.value
|
||||
if account_obj.status_of_secondary is not None else None),
|
||||
primary_location=account_obj.primary_location
|
||||
primary_location=account_obj.primary_location,
|
||||
https_only=account_obj.enable_https_traffic_only
|
||||
)
|
||||
account_dict['custom_domain'] = None
|
||||
if account_obj.custom_domain:
|
||||
|
@ -309,10 +403,30 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
account_dict['tags'] = None
|
||||
if account_obj.tags:
|
||||
account_dict['tags'] = account_obj.tags
|
||||
if blob_service_props and blob_service_props.cors and blob_service_props.cors.cors_rules:
|
||||
account_dict['blob_cors'] = [dict(
|
||||
allowed_origins=[to_native(y) for y in x.allowed_origins],
|
||||
allowed_methods=[to_native(y) for y in x.allowed_methods],
|
||||
max_age_in_seconds=x.max_age_in_seconds,
|
||||
exposed_headers=[to_native(y) for y in x.exposed_headers],
|
||||
allowed_headers=[to_native(y) for y in x.allowed_headers]
|
||||
) for x in blob_service_props.cors.cors_rules]
|
||||
return account_dict
|
||||
|
||||
def update_account(self):
|
||||
self.log('Update storage account {0}'.format(self.name))
|
||||
if bool(self.https_only) != bool(self.account_dict.get('https_only')):
|
||||
self.results['changed'] = True
|
||||
self.account_dict['https_only'] = self.https_only
|
||||
if not self.check_mode:
|
||||
try:
|
||||
parameters = self.storage_models.StorageAccountUpdateParameters(enable_https_traffic_only=self.https_only)
|
||||
self.storage_client.storage_accounts.update(self.resource_group,
|
||||
self.name,
|
||||
parameters)
|
||||
except Exception as exc:
|
||||
self.fail("Failed to update account type: {0}".format(str(exc)))
|
||||
|
||||
if self.account_type:
|
||||
if self.account_type != self.account_dict['sku_name']:
|
||||
# change the account type
|
||||
|
@ -332,7 +446,7 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
try:
|
||||
self.log("sku_name: %s" % self.account_dict['sku_name'])
|
||||
self.log("sku_tier: %s" % self.account_dict['sku_tier'])
|
||||
sku = self.storage_models.Sku(SkuName(self.account_dict['sku_name']))
|
||||
sku = self.storage_models.Sku(name=SkuName(self.account_dict['sku_name']))
|
||||
sku.tier = self.storage_models.SkuTier(self.account_dict['sku_tier'])
|
||||
parameters = self.storage_models.StorageAccountUpdateParameters(sku=sku)
|
||||
self.storage_client.storage_accounts.update(self.resource_group,
|
||||
|
@ -377,6 +491,11 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
except Exception as exc:
|
||||
self.fail("Failed to update tags: {0}".format(str(exc)))
|
||||
|
||||
if self.blob_cors and not compare_cors(self.account_dict.get('blob_cors', []), self.blob_cors):
|
||||
self.results['changed'] = True
|
||||
if not self.check_mode:
|
||||
self.set_blob_cors()
|
||||
|
||||
def create_account(self):
|
||||
self.log("Creating account {0}".format(self.name))
|
||||
|
||||
|
@ -398,16 +517,22 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
account_type=self.account_type,
|
||||
name=self.name,
|
||||
resource_group=self.resource_group,
|
||||
enable_https_traffic_only=self.https_only,
|
||||
tags=dict()
|
||||
)
|
||||
if self.tags:
|
||||
account_dict['tags'] = self.tags
|
||||
if self.blob_cors:
|
||||
account_dict['blob_cors'] = self.blob_cors
|
||||
return account_dict
|
||||
sku = self.storage_models.Sku(self.storage_models.SkuName(self.account_type))
|
||||
sku = self.storage_models.Sku(name=self.storage_models.SkuName(self.account_type))
|
||||
sku.tier = self.storage_models.SkuTier.standard if 'Standard' in self.account_type else \
|
||||
self.storage_models.SkuTier.premium
|
||||
parameters = self.storage_models.StorageAccountCreateParameters(sku, self.kind, self.location,
|
||||
tags=self.tags, access_tier=self.access_tier)
|
||||
parameters = self.storage_models.StorageAccountCreateParameters(sku=sku,
|
||||
kind=self.kind,
|
||||
location=self.location,
|
||||
tags=self.tags,
|
||||
access_tier=self.access_tier)
|
||||
self.log(str(parameters))
|
||||
try:
|
||||
poller = self.storage_client.storage_accounts.create(self.resource_group, self.name, parameters)
|
||||
|
@ -415,13 +540,15 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
except CloudError as e:
|
||||
self.log('Error creating storage account.')
|
||||
self.fail("Failed to create account: {0}".format(str(e)))
|
||||
if self.blob_cors:
|
||||
self.set_blob_cors()
|
||||
# the poller doesn't actually return anything
|
||||
return self.get_account()
|
||||
|
||||
def delete_account(self):
|
||||
if self.account_dict['provisioning_state'] == self.storage_models.ProvisioningState.succeeded.value and \
|
||||
self.account_has_blob_containers() and self.force:
|
||||
self.fail("Account contains blob containers. Is it in use? Use the force option to attempt deletion.")
|
||||
not self.force_delete_nonempty and self.account_has_blob_containers():
|
||||
self.fail("Account contains blob containers. Is it in use? Use the force_delete_nonempty option to attempt deletion.")
|
||||
|
||||
self.log('Delete storage account {0}'.format(self.name))
|
||||
self.results['changed'] = True
|
||||
|
@ -451,6 +578,15 @@ class AzureRMStorageAccount(AzureRMModuleBase):
|
|||
return True
|
||||
return False
|
||||
|
||||
def set_blob_cors(self):
|
||||
try:
|
||||
cors_rules = self.storage_models.CorsRules(cors_rules=[self.storage_models.CorsRule(**x) for x in self.blob_cors])
|
||||
self.storage_client.blob_services.set_service_properties(self.resource_group,
|
||||
self.name,
|
||||
self.storage_models.BlobServiceProperties(cors=cors_rules))
|
||||
except Exception as exc:
|
||||
self.fail("Failed to set CORS rules: {0}".format(str(exc)))
|
||||
|
||||
|
||||
def main():
|
||||
AzureRMStorageAccount()
|
||||
|
|
|
@ -37,6 +37,18 @@ options:
|
|||
tags:
|
||||
description:
|
||||
- Limit results by providing a list of tags. Format tags as 'key' or 'key:value'.
|
||||
show_connection_string:
|
||||
description:
|
||||
- Show the connection string for each of the storageaccount's endpoints.
|
||||
- Note that it will cost a lot of time when list all storageaccount rather than query a single one.
|
||||
type: bool
|
||||
version_added: "2.8"
|
||||
show_blob_cors:
|
||||
description:
|
||||
- Show the blob CORS settings for each of the storageaccount's blob.
|
||||
- Note that it will cost a lot time when list all storageaccount rather than querry a single one.
|
||||
type: bool
|
||||
version_added: "2.8"
|
||||
|
||||
extends_documentation_fragment:
|
||||
- azure
|
||||
|
@ -89,6 +101,176 @@ azure_storageaccounts:
|
|||
"tags": {},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
}]
|
||||
storageaccounts:
|
||||
description: List of storage account dicts in resource module's parameter format.
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
id:
|
||||
description:
|
||||
- Resource ID.
|
||||
sample: "/subscriptions/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX/resourceGroups/testing/providers/Microsoft.Storage/storageAccounts/testaccount001"
|
||||
name:
|
||||
description:
|
||||
- Name of the storage account to update or create.
|
||||
sample: "testaccount001"
|
||||
location:
|
||||
description:
|
||||
- Valid azure location. Defaults to location of the resource group.
|
||||
sample: eastus
|
||||
account_type:
|
||||
description:
|
||||
- Type of storage account.
|
||||
- "NOTE: Standard_ZRS and Premium_LRS accounts cannot be changed to other account types."
|
||||
- Other account types cannot be changed to Standard_ZRS or Premium_LRS.
|
||||
sample: Standard_ZRS
|
||||
custom_domain:
|
||||
description:
|
||||
- User domain assigned to the storage account.
|
||||
- Must be a dictionary with 'name' and 'use_sub_domain' keys where 'name' is the CNAME source.
|
||||
type: complex
|
||||
contains:
|
||||
name:
|
||||
description:
|
||||
- CNAME source.
|
||||
sample: testaccount
|
||||
use_sub_domain:
|
||||
description:
|
||||
- whether to use sub domain.
|
||||
sample: true
|
||||
kind:
|
||||
description:
|
||||
- The 'kind' of storage.
|
||||
sample: Storage
|
||||
access_tier:
|
||||
description:
|
||||
- The access tier for this storage account.
|
||||
sample: Hot
|
||||
https_only:
|
||||
description:
|
||||
- Allows https traffic only to storage service if sets to true.
|
||||
sample: false
|
||||
provisioning_state:
|
||||
description:
|
||||
- Gets the status of the storage account at the time the operation was called.
|
||||
- Possible values include 'Creating', 'ResolvingDNS', 'Succeeded'.
|
||||
sample: Succeeded
|
||||
secondary_location:
|
||||
description:
|
||||
- Gets the location of the geo-replicated secondary for the storage account.
|
||||
- Only available if the accountType is Standard_GRS or Standard_RAGRS.
|
||||
sample: westus
|
||||
status_of_primary:
|
||||
description:
|
||||
- Gets the status indicating whether the primary location of the storage account is available or unavailable.
|
||||
sample: available
|
||||
status_of_secondary:
|
||||
description:
|
||||
- Gets the status indicating whether the secondary location of the storage account is available or unavailable.
|
||||
sample: available
|
||||
primary_location:
|
||||
description:
|
||||
- Gets the location of the primary data center for the storage account.
|
||||
sample: eastus
|
||||
primary_endpoints:
|
||||
description:
|
||||
- Gets the URLs that are used to perform a retrieval of a public blob, queue, or table object.
|
||||
- Note that Standard_ZRS and Premium_LRS accounts only return the blob endpoint.
|
||||
type: complex
|
||||
contains:
|
||||
blob:
|
||||
description:
|
||||
- Gets the primary blob endpoint and connection string.
|
||||
type: complex
|
||||
contains:
|
||||
endpoint:
|
||||
description:
|
||||
- Gets the primary blob endpoint.
|
||||
sample: "https://testaccount001.blob.core.windows.net/"
|
||||
connectionstring:
|
||||
description:
|
||||
- Connectionstring of the blob endpoint
|
||||
sample: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=X;AccountKey=X;BlobEndpoint=X"
|
||||
queue:
|
||||
description:
|
||||
- Gets the primary queue endpoint and connection string.
|
||||
type: complex
|
||||
contains:
|
||||
endpoint:
|
||||
description:
|
||||
- Gets the primary queue endpoint.
|
||||
sample: "https://testaccount001.queue.core.windows.net/"
|
||||
connectionstring:
|
||||
description:
|
||||
- Connectionstring of the queue endpoint
|
||||
sample: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=X;AccountKey=X;QueueEndpoint=X"
|
||||
table:
|
||||
description:
|
||||
- Gets the primary table endpoint and connection string.
|
||||
type: complex
|
||||
contains:
|
||||
endpoint:
|
||||
description:
|
||||
- Gets the primary table endpoint.
|
||||
sample: "https://testaccount001.table.core.windows.net/"
|
||||
connectionstring:
|
||||
description:
|
||||
- Connectionstring of the table endpoint
|
||||
sample: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=X;AccountKey=X;TableEndpoint=X"
|
||||
secondary_endpoints:
|
||||
description:
|
||||
- Gets the URLs that are used to perform a retrieval of a public blob, queue, or table object from the secondary location.
|
||||
- Only available if the SKU name is Standard_RAGRS.
|
||||
type: complex
|
||||
contains:
|
||||
blob:
|
||||
description:
|
||||
- Gets the secondary blob endpoint and connection string.
|
||||
type: complex
|
||||
contains:
|
||||
endpoint:
|
||||
description:
|
||||
- Gets the secondary blob endpoint.
|
||||
sample: "https://testaccount001.blob.core.windows.net/"
|
||||
connectionstring:
|
||||
description:
|
||||
- Connectionstring of the blob endpoint
|
||||
sample: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=X;AccountKey=X;BlobEndpoint=X"
|
||||
queue:
|
||||
description:
|
||||
- Gets the secondary queue endpoint and connection string.
|
||||
type: complex
|
||||
contains:
|
||||
endpoint:
|
||||
description:
|
||||
- Gets the secondary queue endpoint.
|
||||
sample: "https://testaccount001.queue.core.windows.net/"
|
||||
connectionstring:
|
||||
description:
|
||||
- Connectionstring of the queue endpoint
|
||||
sample: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=X;AccountKey=X;QueueEndpoint=X"
|
||||
table:
|
||||
description:
|
||||
- Gets the secondary table endpoint and connection string.
|
||||
type: complex
|
||||
contains:
|
||||
endpoint:
|
||||
description:
|
||||
- Gets the secondary table endpoint.
|
||||
sample: "https://testaccount001.table.core.windows.net/"
|
||||
connectionstring:
|
||||
description:
|
||||
- Connectionstring of the table endpoint
|
||||
sample: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=X;AccountKey=X;TableEndpoint=X"
|
||||
tags:
|
||||
description:
|
||||
- Resource tags.
|
||||
type: dict
|
||||
sample: { "tag1": "abc" }
|
||||
blob_cors:
|
||||
description:
|
||||
- Blob CORS of blob.
|
||||
type: list
|
||||
'''
|
||||
|
||||
try:
|
||||
|
@ -98,6 +280,7 @@ except Exception:
|
|||
pass
|
||||
|
||||
from ansible.module_utils.azure_rm_common import AzureRMModuleBase
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
AZURE_OBJECT_CLASS = 'StorageAccount'
|
||||
|
@ -110,16 +293,21 @@ class AzureRMStorageAccountFacts(AzureRMModuleBase):
|
|||
name=dict(type='str'),
|
||||
resource_group=dict(type='str', aliases=['resource_group_name']),
|
||||
tags=dict(type='list'),
|
||||
show_connection_string=dict(type='bool'),
|
||||
show_blob_cors=dict(type='bool')
|
||||
)
|
||||
|
||||
self.results = dict(
|
||||
changed=False,
|
||||
ansible_facts=dict(azure_storageaccounts=[])
|
||||
ansible_facts=dict(azure_storageaccounts=[]),
|
||||
storageaccounts=[]
|
||||
)
|
||||
|
||||
self.name = None
|
||||
self.resource_group = None
|
||||
self.tags = None
|
||||
self.show_connection_string = None
|
||||
self.show_blob_cors = None
|
||||
|
||||
super(AzureRMStorageAccountFacts, self).__init__(self.module_arg_spec,
|
||||
supports_tags=False,
|
||||
|
@ -133,29 +321,29 @@ class AzureRMStorageAccountFacts(AzureRMModuleBase):
|
|||
if self.name and not self.resource_group:
|
||||
self.fail("Parameter error: resource group required when filtering by name.")
|
||||
|
||||
results = []
|
||||
if self.name:
|
||||
self.results['ansible_facts']['azure_storageaccounts'] = self.get_account()
|
||||
results = self.get_account()
|
||||
elif self.resource_group:
|
||||
self.results['ansible_facts']['azure_storageaccounts'] = self.list_resource_group()
|
||||
results = self.list_resource_group()
|
||||
else:
|
||||
self.results['ansible_facts']['azure_storageaccounts'] = self.list_all()
|
||||
results = self.list_all()
|
||||
|
||||
filtered = self.filter_tag(results)
|
||||
|
||||
self.results['ansible_facts']['azure_storageaccounts'] = self.serialize(filtered)
|
||||
self.results['ansible_facts']['storageaccounts'] = self.format_to_dict(filtered)
|
||||
return self.results
|
||||
|
||||
def get_account(self):
|
||||
self.log('Get properties for account {0}'.format(self.name))
|
||||
account = None
|
||||
result = []
|
||||
|
||||
try:
|
||||
account = self.storage_client.storage_accounts.get_properties(self.resource_group, self.name)
|
||||
return [account]
|
||||
except CloudError:
|
||||
pass
|
||||
|
||||
if account and self.has_tags(account.tags, self.tags):
|
||||
result = [self.serialize_obj(account, AZURE_OBJECT_CLASS)]
|
||||
|
||||
return result
|
||||
return []
|
||||
|
||||
def list_resource_group(self):
|
||||
self.log('List items')
|
||||
|
@ -164,11 +352,7 @@ class AzureRMStorageAccountFacts(AzureRMModuleBase):
|
|||
except Exception as exc:
|
||||
self.fail("Error listing for resource group {0} - {1}".format(self.resource_group, str(exc)))
|
||||
|
||||
results = []
|
||||
for item in response:
|
||||
if self.has_tags(item.tags, self.tags):
|
||||
results.append(self.serialize_obj(item, AZURE_OBJECT_CLASS))
|
||||
return results
|
||||
return response
|
||||
|
||||
def list_all(self):
|
||||
self.log('List all items')
|
||||
|
@ -177,11 +361,110 @@ class AzureRMStorageAccountFacts(AzureRMModuleBase):
|
|||
except Exception as exc:
|
||||
self.fail("Error listing all items - {0}".format(str(exc)))
|
||||
|
||||
results = []
|
||||
for item in response:
|
||||
if self.has_tags(item.tags, self.tags):
|
||||
results.append(self.serialize_obj(item, AZURE_OBJECT_CLASS))
|
||||
return results
|
||||
return response
|
||||
|
||||
def filter_tag(self, raw):
|
||||
return [item for item in raw if self.has_tags(item.tags, self.tags)]
|
||||
|
||||
def serialize(self, raw):
|
||||
return [self.serialize_obj(item, AZURE_OBJECT_CLASS) for item in raw]
|
||||
|
||||
def format_to_dict(self, raw):
|
||||
return [self.account_obj_to_dict(item) for item in raw]
|
||||
|
||||
def account_obj_to_dict(self, account_obj, blob_service_props=None):
|
||||
account_dict = dict(
|
||||
id=account_obj.id,
|
||||
name=account_obj.name,
|
||||
location=account_obj.location,
|
||||
access_tier=(account_obj.access_tier.value
|
||||
if account_obj.access_tier is not None else None),
|
||||
account_type=account_obj.sku.name.value,
|
||||
kind=account_obj.kind.value if account_obj.kind else None,
|
||||
provisioning_state=account_obj.provisioning_state.value,
|
||||
secondary_location=account_obj.secondary_location,
|
||||
status_of_primary=(account_obj.status_of_primary.value
|
||||
if account_obj.status_of_primary is not None else None),
|
||||
status_of_secondary=(account_obj.status_of_secondary.value
|
||||
if account_obj.status_of_secondary is not None else None),
|
||||
primary_location=account_obj.primary_location,
|
||||
https_only=account_obj.enable_https_traffic_only
|
||||
)
|
||||
|
||||
id_dict = self.parse_resource_to_dict(account_obj.id)
|
||||
account_dict['resource_group'] = id_dict.get('resource_group')
|
||||
account_key = self.get_connectionstring(account_dict['resource_group'], account_dict['name'])
|
||||
account_dict['custom_domain'] = None
|
||||
if account_obj.custom_domain:
|
||||
account_dict['custom_domain'] = dict(
|
||||
name=account_obj.custom_domain.name,
|
||||
use_sub_domain=account_obj.custom_domain.use_sub_domain
|
||||
)
|
||||
|
||||
account_dict['primary_endpoints'] = None
|
||||
if account_obj.primary_endpoints:
|
||||
account_dict['primary_endpoints'] = dict(
|
||||
blob=self.format_endpoint_dict(account_dict['name'], account_key[0], account_obj.primary_endpoints.blob, 'blob'),
|
||||
queue=self.format_endpoint_dict(account_dict['name'], account_key[0], account_obj.primary_endpoints.queue, 'queue'),
|
||||
table=self.format_endpoint_dict(account_dict['name'], account_key[0], account_obj.primary_endpoints.table, 'table')
|
||||
)
|
||||
account_dict['secondary_endpoints'] = None
|
||||
if account_obj.secondary_endpoints:
|
||||
account_dict['secondary_endpoints'] = dict(
|
||||
blob=self.format_endpoint_dict(account_dict['name'], account_key[1], account_obj.primary_endpoints.blob, 'blob'),
|
||||
queue=self.format_endpoint_dict(account_dict['name'], account_key[1], account_obj.primary_endpoints.queue, 'queue'),
|
||||
table=self.format_endpoint_dict(account_dict['name'], account_key[1], account_obj.primary_endpoints.table, 'table'),
|
||||
)
|
||||
account_dict['tags'] = None
|
||||
if account_obj.tags:
|
||||
account_dict['tags'] = account_obj.tags
|
||||
blob_service_props = self.get_blob_service_props(account_dict['resource_group'], account_dict['name'])
|
||||
if blob_service_props and blob_service_props.cors and blob_service_props.cors.cors_rules:
|
||||
account_dict['blob_cors'] = [dict(
|
||||
allowed_origins=to_native(x.allowed_origins),
|
||||
allowed_methods=to_native(x.allowed_methods),
|
||||
max_age_in_seconds=x.max_age_in_seconds,
|
||||
exposed_headers=to_native(x.exposed_headers),
|
||||
allowed_headers=to_native(x.allowed_headers)
|
||||
) for x in blob_service_props.cors.cors_rules]
|
||||
return account_dict
|
||||
|
||||
def format_endpoint_dict(self, name, key, endpoint, storagetype, protocol='https'):
|
||||
result = dict(endpoint=endpoint)
|
||||
if key:
|
||||
result['connectionstring'] = 'DefaultEndpointsProtocol={0};EndpointSuffix={1};AccountName={2};AccountKey={3};{4}Endpoint={5}'.format(
|
||||
protocol,
|
||||
self._cloud_environment.suffixes.storage_endpoint,
|
||||
name,
|
||||
key,
|
||||
str.title(storagetype),
|
||||
endpoint)
|
||||
return result
|
||||
|
||||
def get_blob_service_props(self, resource_group, name):
|
||||
if not self.show_blob_cors:
|
||||
return None
|
||||
try:
|
||||
blob_service_props = self.storage_client.blob_services.get_service_properties(resource_group, name)
|
||||
return blob_service_props
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
def get_connectionstring(self, resource_group, name):
|
||||
keys = ['', '']
|
||||
if not self.show_connection_string:
|
||||
return keys
|
||||
try:
|
||||
cred = self.storage_client.storage_accounts.list_keys(resource_group, name)
|
||||
# get the following try catch from CLI
|
||||
try:
|
||||
keys = [cred.keys[0].value, cred.keys[1].value]
|
||||
except AttributeError:
|
||||
keys = [cred.key1, cred.key2]
|
||||
except Exception:
|
||||
pass
|
||||
return keys
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -1779,10 +1779,10 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
self.log("Storage account {0} found.".format(storage_account_name))
|
||||
self.check_provisioning_state(account)
|
||||
return account
|
||||
sku = self.storage_models.Sku(self.storage_models.SkuName.standard_lrs)
|
||||
sku = self.storage_models.Sku(name=self.storage_models.SkuName.standard_lrs)
|
||||
sku.tier = self.storage_models.SkuTier.standard
|
||||
kind = self.storage_models.Kind.storage
|
||||
parameters = self.storage_models.StorageAccountCreateParameters(sku, kind, self.location)
|
||||
parameters = self.storage_models.StorageAccountCreateParameters(sku=sku, kind=kind, location=self.location)
|
||||
self.log("Creating storage account {0} in location {1}".format(storage_account_name, self.location))
|
||||
self.results['actions'].append("Created storage account {0}".format(storage_account_name))
|
||||
try:
|
||||
|
|
|
@ -19,7 +19,7 @@ azure-mgmt-redis==5.0.0
|
|||
azure-mgmt-resource==1.2.2
|
||||
azure-mgmt-rdbms==1.4.1
|
||||
azure-mgmt-sql==0.10.0
|
||||
azure-mgmt-storage==1.5.0
|
||||
azure-mgmt-storage==3.1.0
|
||||
azure-mgmt-trafficmanager==0.50.0
|
||||
azure-mgmt-web==0.32.0
|
||||
azure-nspkg==2.0.0
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
resource_group: "{{ resource_group }}"
|
||||
name: "{{ storage_account }}"
|
||||
state: absent
|
||||
force_delete_nonempty: True
|
||||
|
||||
- name: Create new storage account
|
||||
azure_rm_storageaccount:
|
||||
|
@ -25,6 +26,19 @@
|
|||
name: "{{ storage_account }}"
|
||||
account_type: Standard_LRS
|
||||
append_tags: no
|
||||
blob_cors:
|
||||
- allowed_origins:
|
||||
- http://www.example.com/
|
||||
allowed_methods:
|
||||
- GET
|
||||
- POST
|
||||
allowed_headers:
|
||||
- x-ms-meta-data*
|
||||
- x-ms-meta-target*
|
||||
- x-ms-meta-abc
|
||||
exposed_headers:
|
||||
- x-ms-meta-*
|
||||
max_age_in_seconds: 200
|
||||
tags:
|
||||
test: test
|
||||
galaxy: galaxy
|
||||
|
@ -35,6 +49,35 @@
|
|||
that:
|
||||
- output.changed
|
||||
- output.state.id is defined
|
||||
- output.state.blob_cors | length == 1
|
||||
|
||||
- name: Create new storage account (idempotence)
|
||||
azure_rm_storageaccount:
|
||||
resource_group: "{{ resource_group }}"
|
||||
name: "{{ storage_account }}"
|
||||
account_type: Standard_LRS
|
||||
append_tags: no
|
||||
blob_cors:
|
||||
- allowed_origins:
|
||||
- http://www.example.com/
|
||||
allowed_methods:
|
||||
- GET
|
||||
- POST
|
||||
allowed_headers:
|
||||
- x-ms-meta-data*
|
||||
- x-ms-meta-target*
|
||||
- x-ms-meta-abc
|
||||
exposed_headers:
|
||||
- x-ms-meta-*
|
||||
max_age_in_seconds: 200
|
||||
tags:
|
||||
test: test
|
||||
galaxy: galaxy
|
||||
register: output
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- not output.changed
|
||||
|
||||
- name: Gather facts by tags
|
||||
azure_rm_storageaccount_facts:
|
||||
|
@ -69,22 +112,6 @@
|
|||
- name: Assert CNAME failure
|
||||
assert: { that: "'custom domain name could not be verified' in change_account['msg']" }
|
||||
|
||||
- name: Update account tags
|
||||
azure_rm_storageaccount:
|
||||
resource_group: "{{ resource_group }}"
|
||||
name: "{{ storage_account }}"
|
||||
append_tags: no
|
||||
tags:
|
||||
testing: testing
|
||||
delete: never
|
||||
galaxy: 'no'
|
||||
register: output
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "output.state.tags | length == 3"
|
||||
- "output.state.tags.galaxy == 'no'"
|
||||
|
||||
- name: Update account tags
|
||||
azure_rm_storageaccount:
|
||||
resource_group: "{{ resource_group }}"
|
||||
|
@ -105,10 +132,17 @@
|
|||
azure_rm_storageaccount_facts:
|
||||
resource_group: "{{ resource_group }}"
|
||||
name: "{{ storage_account }}"
|
||||
show_connection_string: True
|
||||
show_blob_cors: True
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "azure_storageaccounts| length == 1"
|
||||
- "storageaccounts | length == 1"
|
||||
- not storageaccounts[0].custom_domain
|
||||
- storageaccounts[0].account_type == "Standard_GRS"
|
||||
- storageaccounts[0].primary_endpoints.blob.connectionstring
|
||||
- storageaccounts[0].blob_cors
|
||||
|
||||
- name: Gather facts
|
||||
azure_rm_storageaccount_facts:
|
||||
|
|
|
@ -165,6 +165,7 @@
|
|||
name: "{{ storage_account }}"
|
||||
type: Standard_LRS
|
||||
state: absent
|
||||
force_delete_nonempty: true
|
||||
|
||||
- name: Delete Network Security Group that allows SSH
|
||||
azure_rm_securitygroup:
|
||||
|
|
|
@ -19,7 +19,7 @@ azure-mgmt-redis==5.0.0
|
|||
azure-mgmt-resource==1.2.2
|
||||
azure-mgmt-rdbms==1.4.1
|
||||
azure-mgmt-sql==0.10.0
|
||||
azure-mgmt-storage==1.5.0
|
||||
azure-mgmt-storage==3.1.0
|
||||
azure-mgmt-trafficmanager==0.50.0
|
||||
azure-mgmt-web==0.32.0
|
||||
azure-nspkg==2.0.0
|
||||
|
|
Loading…
Reference in a new issue