class MU::Cloud::Azure
Support for Microsoft Azure
as a provisioning layer.
Attributes
Public Class Methods
Resolve the administrative Cloud
Storage bucket for a given credential set, or return a default. @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [String]
# File modules/mu/providers/azure.rb, line 546 def self.adminBucketName(credentials = nil) "TODO" end
Resolve the administrative Cloud
Storage bucket for a given credential set, or return a default. @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [String]
# File modules/mu/providers/azure.rb, line 554 def self.adminBucketUrl(credentials = nil) "TODO" end
The Azure
ApiManagement API @param model [<Azure::Apis::ApiManagement::Mgmt::V2019_01_01::Models>]: If specified, will return the class ::Azure::Apis::ApiManagement::Mgmt::V2019_01_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 779 def self.apis(model = nil, alt_object: nil, credentials: nil, model_version: "V2019_01_01") require 'azure_mgmt_api_management' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("ApiManagement").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@apis_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "ApiManagement", credentials: credentials, subclass: alt_object) end return @@apis_api[credentials] end
The Azure
Billing API @param model [<Azure::Apis::Billing::Mgmt::V2018_03_01_preview::Models>]: If specified, will return the class ::Azure::Apis::Billing::Mgmt::V2018_03_01_preview::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 924 def self.billing(model = nil, alt_object: nil, credentials: nil, model_version: "V2018_03_01_preview") require 'azure_mgmt_billing' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Billing").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@billing_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Billing", credentials: credentials, subclass: alt_object) end return @@billing_api[credentials] end
Purge cloud-specific deploy meta-artifacts (SSH keys, resource groups, etc) @param deploy_id [String] @param credentials [String]: The credential set (subscription, effectively) in which to operate
# File modules/mu/providers/azure.rb, line 400 def self.cleanDeploy(deploy_id, credentials: nil, noop: false) threads = [] @@rg_semaphore.synchronize { MU::Cloud::Azure.resources(credentials: credentials).resource_groups.list.each { |rg| if rg.tags and rg.tags["MU-ID"] == deploy_id threads << Thread.new(rg) { |rg_obj| Thread.abort_on_exception = false MU.log "Removing resource group #{rg_obj.name} from #{rg_obj.location}" if !noop MU::Cloud::Azure.resources(credentials: credentials).resource_groups.delete(rg_obj.name) end } end } threads.each { |t| t.join } } end
The Azure
Compute API @param model [<Azure::Apis::Compute::Mgmt::V2019_04_01::Models>]: If specified, will return the class ::Azure::Apis::Compute::Mgmt::V2019_04_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 725 def self.compute(model = nil, alt_object: nil, credentials: nil, model_version: "V2019_03_01") require 'azure_mgmt_compute' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Compute").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@compute_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Compute", credentials: credentials, subclass: alt_object) end return @@compute_api[credentials] end
A non-working example configuration
# File modules/mu/providers/azure.rb, line 337 def self.config_example sample = hosted_config sample ||= { "region" => "eastus", "subscriptionId" => "99999999-9999-9999-9999-999999999999", } sample["credentials_file"] = "~/.azure/credentials" sample["log_bucket_name"] = "my-mu-s3-bucket" sample end
The Azure
ContainerService API @param model [<Azure::Apis::ContainerService::Mgmt::V2019_04_01::Models>]: If specified, will return the class ::Azure::Apis::ContainerService::Mgmt::V2019_04_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 869 def self.containers(model = nil, alt_object: nil, credentials: nil, model_version: "V2019_04_01") require 'azure_mgmt_container_service' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("ContainerService").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@containers_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "ContainerService", credentials: credentials, subclass: alt_object) end return @@containers_api[credentials] end
Azure
resources are deployed into a containing artifact called a Resource Group
, which we will map 1:1 with Mu deployments @param name [String]: A name for this resource group @param region [String]: The region in which to create this resource group
# File modules/mu/providers/azure.rb, line 424 def self.createResourceGroup(name, region, credentials: nil) rg_obj = MU::Cloud::Azure.resources(:ResourceGroup).new rg_obj.location = region rg_obj.tags = MU::MommaCat.listStandardTags rg_obj.tags.reject! { |_k, v| v.nil? } MU::Cloud::Azure.resources(credentials: credentials).resource_groups.list.each { |rg| if rg.name == name and rg.location == region and rg.tags == rg_obj.tags MU.log "Resource group #{name} already exists in #{region}", MU::DEBUG, details: rg_obj return rg # already exists? Do nothing end } MU.log "Configuring resource group #{name} in #{region}", details: rg_obj rg = MU::Cloud::Azure.resources(credentials: credentials).resource_groups.create_or_update( name, rg_obj ) rg end
Arguably this should be a first class resource, but for now we'll do it here since we're going to have a generic deployment vault in every resource group. @param rg [String]: The name of the resource group in which we'll reside @param region [String]: The region in which we'll reside @param deploy [MU::MommaCat]: The deployment which we serve @param credentials [String]:
# File modules/mu/providers/azure.rb, line 373 def self.createVault(rg, region, deploy, credentials: nil) cred_hash = MU::Cloud::Azure.getSDKOptions(credentials) vaultname = deploy.getResourceName(region, max_length: 23, disallowed_chars: /[^a-z0-9-]/i, never_gen_unique: true) MU::Cloud::Azure.ensureProvider("Microsoft.KeyVault", credentials: credentials) sku = MU::Cloud::Azure.keyvault(:Sku).new sku.name = "standard" # ...I'm angry about this props = MU::Cloud::Azure.keyvault(:VaultProperties).new props.tenant_id = cred_hash[:tenant_id] props.enabled_for_deployment = true props.sku = sku props.access_policies = [] params = MU::Cloud::Azure.keyvault(:VaultCreateOrUpdateParameters).new params.location = region params.properties = props MU.log "Creating KeyVault #{vaultname} in #{region}" MU::Cloud::Azure.keyvault(credentials: credentials).vaults.create_or_update(rg, vaultname, params) end
Return the $MU_CFG data associated with a particular profile/name/set of credentials. If no account name is specified, will return one flagged as default. Returns nil if Azure
is not configured. Throws an exception if an account name is specified which does not exist. @param name [String]: The name of the key under 'azure' in mu.yaml to return @return [Hash,nil]
# File modules/mu/providers/azure.rb, line 488 def self.credConfig (name = nil, name_only: false) if !$MU_CFG['azure'] or !$MU_CFG['azure'].is_a?(Hash) or $MU_CFG['azure'].size == 0 return @@my_hosted_cfg if @@my_hosted_cfg if hosted? @@my_hosted_cfg = hosted_config return name_only ? "#default" : @@my_hosted_cfg end return nil end if name.nil? $MU_CFG['azure'].each_pair { |set, cfg| if cfg['default'] return name_only ? set : cfg end } else if $MU_CFG['azure'][name] return name_only ? name : $MU_CFG['azure'][name] # elsif @@acct_to_profile_map[name.to_s] # return name_only ? name : @@acct_to_profile_map[name.to_s] end # XXX whatever process might lead us to populate @@acct_to_profile_map with some mappings, like projectname -> account profile, goes here return nil end end
lookup the default subscription that will be used by methods
# File modules/mu/providers/azure.rb, line 241 def self.default_subscription(credentials = nil) cfg = credConfig(credentials) if @@default_subscription.nil? if cfg['subscription'] # MU.log "Found default subscription in mu.yml. Using that..." @@default_subscription = cfg['subscription'] elsif listSubscriptions().length == 1 #MU.log "Found a single subscription on your account. Using that... (This may be incorrect)", MU::WARN, details: e.message @@default_subscription = listSubscriptions()[0] elsif MU::Cloud::Azure.hosted? #MU.log "Found a subscriptionID in my metadata. Using that... (This may be incorrect)", MU::WARN, details: e.message @@default_subscription = get_metadata()['compute']['subscriptionId'] else raise MuError, "Default Subscription was not found. Please run mu-configure to setup a default subscription" end end return @@default_subscription end
Make sure that a feature is enabled (“Registered” in Azure-ese), usually invoked for preview features which are off by default. @param feature_string [String]: The name of a feature, such as WindowsPreview
@param credentials [String]: The credential set (subscription, effectively) in which to operate
# File modules/mu/providers/azure.rb, line 961 def self.ensureFeature(feature_string, credentials: nil) provider, feature = feature_string.split(/\//) feature_state = MU::Cloud::Azure.features(credentials: credentials).features.get(provider, feature) changed = false begin if feature_state if feature_state.properties.state == "Registering" MU.log "Waiting for Feature #{provider}/#{feature} to finish registering", MU::NOTICE, details: feature_state.properties.state sleep 30 elsif feature_state.properties.state == "NotRegistered" MU.log "Registering Feature #{provider}/#{feature}", MU::NOTICE MU::Cloud::Azure.features(credentials: credentials).features.register(provider, feature) changed = true sleep 30 else MU.log "#{provider}/#{feature} registration state: #{feature_state.properties.state}", MU::DEBUG end feature_state = MU::Cloud::Azure.features(credentials: credentials).features.get(provider, feature) end end while feature_state and feature_state.properties.state != "Registered" ensureProvider(provider, credentials: credentials, force: true) if changed end
Make sure that a provider is enabled (“Registered” in Azure-ese). @param provider [String]: Provider name, typically formatted like Microsoft.ContainerService
@param force [Boolean]: Run the operation even if the provider already appears to be enabled @param credentials [String]: The credential set (subscription, effectively) in which to operate
# File modules/mu/providers/azure.rb, line 940 def self.ensureProvider(provider, force: false, credentials: nil) state = MU::Cloud::Azure.resources(credentials: credentials).providers.get(provider) if state.registration_state != "Registered" or force begin if state.registration_state == "NotRegistered" or force MU.log "Registering Provider #{provider}", MU::NOTICE MU::Cloud::Azure.resources(credentials: credentials).providers.register(provider) force = false sleep 30 elsif state.registration_state == "Registering" MU.log "Waiting for Provider #{provider} to finish registering", MU::NOTICE, details: state.registration_state sleep 30 end state = MU::Cloud::Azure.resources(credentials: credentials).providers.get(provider) end while state and state.registration_state != "Registered" end end
The Azure
Features API @param model [<Azure::Apis::Features::Mgmt::V2015_12_01::Models>]: If specified, will return the class ::Azure::Apis::Features::Mgmt::V2015_12_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 851 def self.features(model = nil, alt_object: nil, credentials: nil, model_version: "V2015_12_01") require 'azure_mgmt_features' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Features").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@features_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Features", credentials: credentials, subclass: alt_object) end return @@features_api[credentials] end
Find or allocate a static public IP address resource @param resource_group
[String] @param name [String] @param credentials [String]: The credential set (subscription, effectively) in which to operate @param region [String] @param tags [Hash<String>] @return [Azure::Network::Mgmt::V2019_02_01::Models::PublicIPAddress]
# File modules/mu/providers/azure.rb, line 662 def self.fetchPublicIP(resource_group, name, credentials: nil, region: nil, tags: nil) if !name or !resource_group raise MuError, "Must supply resource_group and name to create or retrieve an Azure PublicIPAddress" end region ||= MU::Cloud::Azure.myRegion(credentials) resp = MU::Cloud::Azure.network(credentials: credentials).public_ipaddresses.get(resource_group, name) if !resp ip_obj = MU::Cloud::Azure.network(:PublicIPAddress).new ip_obj.location = region ip_obj.tags = tags if tags ip_obj.public_ipallocation_method = "Dynamic" MU.log "Allocating PublicIpAddress #{name}", details: ip_obj resp = MU::Cloud::Azure.network(credentials: credentials).public_ipaddresses.create_or_update(resource_group, name, ip_obj) end resp end
Return a random Azure-valid GUID, because for some baffling reason some API calls expect us to roll our own.
# File modules/mu/providers/azure.rb, line 41 def self.genGUID hexchars = Array("a".."f") + Array(0..9) guid_chunks = [] [8, 4, 4, 4, 12].each { |count| guid_chunks << Array.new(count) { hexchars.sample }.join } guid_chunks.join("-") end
Map our SDK authorization options from MU
configuration into an options hash that Azure
understands. Raises an exception if any fields aren't available. @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [Hash]
# File modules/mu/providers/azure.rb, line 596 def self.getSDKOptions(credentials = nil) cfg = credConfig(credentials) if cfg and MU::Cloud::Azure.hosted? token = MU::Cloud::Azure.get_metadata("identity/oauth2/token", "2020-09-01", args: { "resource"=>"https://management.azure.com/" }) if !token MU::Cloud::Azure.get_metadata("identity/oauth2/token", "2020-09-01", args: { "resource"=>"https://management.azure.com/" }, debug: true) raise MuError, "Failed to get machine oauth token" end machine = MU::Cloud::Azure.get_metadata return { credentials: MsRest::TokenCredentials.new(token["access_token"]), client_id: token["client_id"], subscription: machine["compute"]["subscriptionId"], subscription_id: machine["compute"]["subscriptionId"] } end return nil if !cfg map = { #... from mu.yaml-ese to Azure SDK-ese "directory_id" => :tenant_id, "client_id" => :client_id, "client_secret" => :client_secret, "subscription" => :subscription_id } options = {} map.each_pair { |k, v| options[v] = cfg[k] if cfg[k] } if cfg['credentials_file'] file = File.open cfg['credentials_file'] credfile = JSON.load file map.each_pair { |k, v| options[v] = credfile[k] if credfile[k] } end missing = [] map.values.each { |v| missing << v if !options[v] } if missing.size > 0 if (!credentials or credentials == "#default") and hosted? # Let the SDK try to use machine credentials return nil end raise MuError, "Missing fields while trying to load Azure SDK options for credential set #{credentials ? credentials : "<default>" }: #{missing.map { |m| m.to_s }.join(", ")}" end MU.log "Loaded credential set #{credentials ? credentials : "<default>" }", MU::DEBUG, details: options return options end
Fetch (ALL) Azure
instance metadata @return [Hash, nil]
# File modules/mu/providers/azure.rb, line 563 def self.get_metadata(svc = "instance", api_version = "2017-08-01", args: {}, debug: false) loglevel = debug ? MU::NOTICE : MU::DEBUG return @@metadata if svc == "instance" and @@metadata base_url = "http://169.254.169.254/metadata/#{svc}" args["api-version"] = api_version arg_str = args.keys.sort.map { |k| k.to_s+"="+CGI.escape(args[k].to_s) }.join("&") begin Timeout.timeout(2) do resp = JSON.parse(URI.open("#{base_url}?#{arg_str}","Metadata"=>"true").read) MU.log "curl -H Metadata:true "+"#{base_url}?#{arg_str}", loglevel, details: resp if svc != "instance" return resp else @@metadata = resp end end return @@metadata rescue Timeout::Error # MU.log "Timeout querying Azure Metadata" return nil rescue # MU.log "Failed to get Azure MetaData." return nil end end
Return what we think of as a cloud object's habitat. If this is not applicable, such as for a {Habitat} or {Folder}, returns nil. @param cloudobj [MU::Cloud::Azure]: The resource from which to extract the habitat id @return [String,nil]
# File modules/mu/providers/azure.rb, line 477 def self.habitat(cloudobj, nolookup: false, deploy: nil) nil # we don't know how to do anything with subscriptions yet, really end
Alias for #{MU::Cloud::Azure.hosted?}
# File modules/mu/providers/azure.rb, line 186 def self.hosted return MU::Cloud::Azure.hosted? end
UTILITY METHODS Determine whether we (the Mu master, presumably) are hosted in Azure
. @return [Boolean]
# File modules/mu/providers/azure.rb, line 152 def self.hosted? if $MU_CFG and $MU_CFG.has_key?("azure_is_hosted") @@is_in_azure = $MU_CFG["azure_is_hosted"] return $MU_CFG["azure_is_hosted"] end if !@@is_in_azure.nil? return @@is_in_azure end begin metadata = get_metadata() if metadata['compute']['vmId'] @@is_in_azure = true return true else return false end rescue # MU.log "Failed to get Azure MetaData. I assume I am not hosted in Azure", MU::DEBUG, details: resources end @@is_in_azure = false false end
If we're running this cloud, return the $MU_CFG blob we'd use to describe this environment as our target one.
# File modules/mu/providers/azure.rb, line 192 def self.hosted_config return nil if !hosted? region = get_metadata()['compute']['location'] subscription = get_metadata()['compute']['subscriptionId'] { "region" => region, "subscriptionId" => subscription } end
Do cloud-specific deploy instantiation tasks, such as copying SSH keys around, sticking secrets in buckets, creating resource groups, etc @param deploy [MU::MommaCat]
# File modules/mu/providers/azure.rb, line 352 def self.initDeploy(deploy) deploy.credsUsed.each { |creds| next if !credConfig(creds) listRegions.each { |region| next if !deploy.regionsUsed.include?(region) begin rg_obj = createResourceGroup(deploy.deploy_id+"-"+region.upcase, region, credentials: creds) createVault(rg_obj.name, region, deploy, credentials: creds) rescue ::MsRestAzure::AzureOperationError end } } end
The Azure
KeyVault API @param model [<Azure::Apis::KeyVault::Mgmt::V2018_02_14::Models>]: If specified, will return the class ::Azure::Apis::KeyVault::Mgmt::V2018_02_14::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 833 def self.keyvault(model = nil, alt_object: nil, credentials: nil, model_version: "V2018_02_14") require 'azure_mgmt_key_vault' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("KeyVault").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@keyvault_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "KeyVault", credentials: credentials, subclass: alt_object) end return @@keyvault_api[credentials] end
List the Availability Zones associated with a given Azure
region. If no region is given, search the one in which this MU
master server resides (if it resides in this cloud provider's ecosystem). @param region [String]: The region to search. @return [Array<String>]: The Availability Zones in this region.
# File modules/mu/providers/azure.rb, line 323 def self.listAZs(region = nil) az_list = ['1', '2', '3'] # Pulled from this chart: https://docs.microsoft.com/en-us/azure/availability-zones/az-overview#services-support-by-region az_enabled_regions = ['centralus', 'eastus', 'eastus2', 'westus2', 'francecentral', 'northeurope', 'uksouth', 'westeurope', 'japaneast', 'southeastasia'] if not az_enabled_regions.include?(region) az_list = [] end return az_list end
Return the name strings of all known sets of credentials for this cloud @return [Array<String>]
# File modules/mu/providers/azure.rb, line 465 def self.listCredentials if !$MU_CFG['azure'] return hosted? ? ["#default"] : nil end $MU_CFG['azure'].keys end
List all Azure
subscriptions available to our credentials
# File modules/mu/providers/azure.rb, line 51 def self.listHabitats(credentials = nil, use_cache: true) [] end
Query the Azure
API for a list of valid instance types. @param region [String]: Supported machine types can vary from region to region, so we look for the set we're interested in specifically @return [Hash]
# File modules/mu/providers/azure.rb, line 522 def self.listInstanceTypes(region = self.myRegion) return @@instance_types if @@instance_types and @@instance_types[region] if !MU::Cloud::Azure.default_subscription() return {} end @@instance_types ||= {} @@instance_types[region] ||= {} result = MU::Cloud::Azure.compute.virtual_machine_sizes.list(region) raise MuError, "Failed to fetch Azure instance type list" if !result result.value.each { |type| @@instance_types[region][type.name] ||= {} @@instance_types[region][type.name]["memory"] = sprintf("%.1f", type.memory_in_mb/1024.0).to_f @@instance_types[region][type.name]["vcpu"] = type.number_of_cores.to_f @@instance_types[region][type.name]["ecu"] = type.number_of_cores } @@instance_types end
List visible Azure
regions @param credentials [String]: The credential set (subscription, effectively) in which to operate return [Array<String>]
# File modules/mu/providers/azure.rb, line 267 def self.listRegions(us_only = false, credentials: nil) cfg = credConfig(credentials) return nil if !cfg and !hosted? subscription = cfg['subscription'] subscription ||= default_subscription() if @@regions.length() > 0 && subscription == default_subscription() return us_only ? @@regions.reject { |r| !r.match(/us\d?$/) } : @@regions end begin sdk_response = MU::Cloud::Azure.subs(credentials: credentials).subscriptions().list_locations(subscription) rescue StandardError => e MU.log e.inspect, MU::ERR, details: e.backtrace #pp "Error Getting the list of regions from Azure" #TODO: SWITCH THIS TO MU LOG if @@regions and @@regions.size > 0 return us_only ? @@regions.reject { |r| !r.match(/us\d?$/) } : @@regions end raise e end if !sdk_response raise MuError, "Nil response from Azure API attempting list_locations(#{subscription})" end sdk_response.value.each { |region| begin listInstanceTypes(region.name) # use this to filter for broken regions @@regions.push(region.name) rescue APIError => e MU.log "Azure region "+region.name+" does not appear operational, skipping", MU::WARN end } return us_only ? @@regions.reject { |r| !r.match(/us\d?$/) } : @@regions end
List subscriptions visible to the given credentials @param credentials [String]: The credential set (subscription, effectively) in which to operate return [Array<String>]
# File modules/mu/providers/azure.rb, line 306 def self.listSubscriptions(credentials = nil) subscriptions = [] sdk_response = MU::Cloud::Azure.subs(credentials: credentials).subscriptions().list sdk_response.each do |subscription| subscriptions.push(subscription.subscription_id) end return subscriptions end
The Azure
MarketplaceOrdering API @param model [<Azure::Apis::MarketplaceOrdering::Mgmt::V2015_06_01::Models>]: If specified, will return the class ::Azure::Apis::MarketplaceOrdering::Mgmt::V2015_06_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 797 def self.marketplace(model = nil, alt_object: nil, credentials: nil, model_version: "V2015_06_01") require 'azure_mgmt_marketplace_ordering' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Resources").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@marketplace_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "MarketplaceOrdering", credentials: credentials, subclass: alt_object) end return @@marketplace_api[credentials] end
Method that returns the default Azure
region for this Mu Master
@return [string]
# File modules/mu/providers/azure.rb, line 220 def self.myRegion(credentials = nil) if @@myRegion_var return @@myRegion_var end cfg = credConfig(credentials) @@myRegion_var = if cfg['default_region'] cfg['default_region'] elsif MU::Cloud::Azure.hosted? # IF WE ARE HOSTED IN AZURE CHECK FOR THE REGION OF THE INSTANCE metadata = get_metadata() metadata['compute']['location'] else "eastus" end return @@myRegion_var end
The Azure
Network API @param model [<Azure::Apis::Network::Mgmt::V2019_02_01::Models>]: If specified, will return the class ::Azure::Apis::Network::Mgmt::V2019_02_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 743 def self.network(model = nil, alt_object: nil, credentials: nil, model_version: "V2019_02_01") require 'azure_mgmt_network' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Network").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@network_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Network", credentials: credentials, subclass: alt_object) end return @@network_api[credentials] end
Any cloud-specific instance methods we require our resource implementations to have, above and beyond the ones specified by {MU::Cloud} @return [Array<Symbol>]
# File modules/mu/providers/azure.rb, line 81 def self.required_instance_methods [:resource_group] end
A hook that is always called just before any of the instance method of our resource implementations gets invoked, so that we can ensure that repetitive setup tasks (like resolving :resource_group
for Azure
resources) have always been done. @param cloudobj [MU::Cloud] @param deploy [MU::MommaCat]
# File modules/mu/providers/azure.rb, line 61 def self.resourceInitHook(cloudobj, deploy) class << self attr_reader :resource_group end return if !cloudobj rg = if !deploy return if !hosted? MU.myInstanceId.resource_group else region = cloudobj.config['region'] || MU::Cloud::Azure.myRegion(cloudobj.config['credentials']) deploy.deploy_id+"-"+region.upcase end cloudobj.instance_variable_set(:@resource_group, rg) end
The Azure
Resources API @param model [<Azure::Apis::Resources::Mgmt::V2018_05_01::Models>]: If specified, will return the class ::Azure::Apis::Resources::Mgmt::V2018_05_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 815 def self.resources(model = nil, alt_object: nil, credentials: nil, model_version: "V2018_05_01") require 'azure_mgmt_resources' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Resources").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@resources_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Resources", credentials: credentials, subclass: alt_object) end return @@resources_api[credentials] end
Azure's API response objects don't implement to_h
, so we'll wing it ourselves @param struct [MsRestAzure] @return [Hash]
# File modules/mu/providers/azure.rb, line 206 def self.respToHash(struct) hash = {} struct.class.instance_methods(false).each { |m| next if m.to_s.match(/=$/) hash[m.to_s] = struct.send(m) } struct.instance_variables.each { |a| hash[a.to_s.sub(/^@/, "")] = struct.instance_variable_get(a) } hash end
The Azure
ManagedServiceIdentity API @param model [<Azure::Apis::ManagedServiceIdentity::Mgmt::V2015_08_31_preview::Models>]: If specified, will return the class ::Azure::Apis::ManagedServiceIdentity::Mgmt::V2015_08_31_preview::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 887 def self.serviceaccts(model = nil, alt_object: nil, credentials: nil, model_version: "V2015_08_31_preview") require 'azure_mgmt_msi' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("ManagedServiceIdentity").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@service_identity_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "ManagedServiceIdentity", credentials: credentials, subclass: alt_object) end return @@service_identity_api[credentials] end
The Azure
Storage API @param model [<Azure::Apis::Storage::Mgmt::V2019_04_01::Models>]: If specified, will return the class ::Azure::Apis::Storage::Mgmt::V2019_04_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 761 def self.storage(model = nil, alt_object: nil, credentials: nil, model_version: "V2019_04_01") require 'azure_mgmt_storage' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Storage").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@storage_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Storage", credentials: credentials, subclass: alt_object) end return @@storage_api[credentials] end
An alternative version of the Azure
Subscription Manager API, which appears to support subscription creation @param model [<Azure::Apis::Subscriptions::Mgmt::V2018_03_01_preview::Models>]: If specified, will return the class ::Azure::Apis::Subscriptions::Mgmt::V2018_03_01_preview::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 707 def self.subfactory(model = nil, alt_object: nil, credentials: nil, model_version: "V2018_03_01_preview") require 'azure_mgmt_subscriptions' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Subscriptions").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@subscriptions_factory_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Subscriptions", credentials: credentials, profile: "V2018_03_01_preview", subclass: alt_object) end return @@subscriptions_factory_api[credentials] end
BEGIN SDK STUBS
Azure
Subscription Manager API @param model [<Azure::Apis::Subscriptions::Mgmt::V2015_11_01::Models>]: If specified, will return the class ::Azure::Apis::Subscriptions::Mgmt::V2015_11_01::Models::model instead of an API client instance @param model_version [String]: Use an alternative model version supported by the SDK when requesting a model
@param alt_object [String]: Return an instance of something other than the usual API client object @param credentials [String]: The credential set (subscription, effectively) in which to operate @return [MU::Cloud::Azure::SDKClient]
# File modules/mu/providers/azure.rb, line 689 def self.subs(model = nil, alt_object: nil, credentials: nil, model_version: "V2015_11_01") require 'azure_mgmt_subscriptions' if model and model.is_a?(Symbol) return Object.const_get("Azure").const_get("Subscriptions").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model) else @@subscriptions_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "Subscriptions", credentials: credentials, subclass: alt_object) end return @@subscriptions_api[credentials] end
Is this a “real” cloud provider, or a stub like CloudFormation
?
# File modules/mu/providers/azure.rb, line 86 def self.virtual? false end
Plant a Mu deploy secret into a storage bucket somewhere for so our kittens can consume it @param deploy [MU::MommaCat]: The deploy for which we're writing the secret @param value [String]: The contents of the secret
# File modules/mu/providers/azure.rb, line 448 def self.writeDeploySecret(deploy, value, name = nil, credentials: nil) deploy_id = deploy.deploy_id listRegions.each { |region| next if !deploy.regionsUsed.include?(region) rg = deploy_id+"-"+region.upcase vaultname = deploy.getResourceName(region, max_length: 23, disallowed_chars: /[^a-z0-9-]/i, never_gen_unique: true) resp = MU::Cloud::Azure.keyvault(credentials: credentials).vaults.get(rg, vaultname) next if !resp MU.log "vault existence check #{vaultname}", MU::WARN, details: resp } end