modules/mu/clouds/aws.rb in cloud-mu-3.1.3 vs modules/mu/clouds/aws.rb in cloud-mu-3.1.4
- old
+ new
@@ -36,12 +36,12 @@
# 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]
- def self.resourceInitHook(cloudobj, deploy)
+ # @param _deploy [MU::MommaCat]
+ def self.resourceInitHook(cloudobj, _deploy)
class << self
attr_reader :cloudformation_data
end
cloudobj.instance_variable_set(:@cloudformation_data, {})
end
@@ -61,11 +61,10 @@
cred_cfg = credConfig(name)
if cred_cfg.nil?
return nil
end
- loaded = false
cred_obj = nil
if cred_cfg['access_key'] and cred_cfg['access_secret'] and
# access key and secret just sitting in mu.yaml
!cred_cfg['access_key'].empty? and
!cred_cfg['access_secret'].empty?
@@ -135,15 +134,26 @@
if !cred_obj and hosted?
# assume we've got an IAM profile and hope for the best
ENV.delete('AWS_ACCESS_KEY_ID')
ENV.delete('AWS_SECRET_ACCESS_KEY')
- cred_obj = Aws::InstanceProfileCredentials.new
+ retries = 0
+ begin
+ cred_obj = Aws::InstanceProfileCredentials.new
+ if cred_obj.nil?
+ retries += 1
+ MU.log "Failed to fetch AWS instance profile credentials, attempt #{retries.to_s}/10", MU::WARN
+ sleep 3
+ end
+ end while cred_obj.nil? and retries < 10
# if name.nil?
# Aws.config = {region: ENV['EC2_REGION']}
# end
end
+if cred_obj.nil?
+MU.log "cred_obj is nil and hosted? says #{hosted?.to_s}", MU::WARN, details: name
+end
if name.nil?
@@creds_loaded["#default"] = cred_obj
else
@@creds_loaded[name] = cred_obj
@@ -281,56 +291,17 @@
}
]
)
end
- # Tag EC2 resources.
- #
- # @param resources [Array<String>]: The cloud provider identifier of the resource to tag
- # @param key [String]: The name of the tag to create
- # @param value [String]: The value of the tag
- # @param region [String]: The cloud provider region
- # @return [void,<Hash>]
- def self.createTag(key, value, resources = [], region: myRegion, credentials: nil)
-
- if !MU::Cloud::CloudFormation.emitCloudFormation
- begin
- MU::Cloud::AWS.ec2(region: region, credentials: credentials).create_tags(
- resources: resources,
- tags: [
- {
- key: key,
- value: value
- }
- ]
- )
- rescue Aws::EC2::Errors::ServiceError => e
- MU.log "Got #{e.inspect} tagging #{resources.size.to_s} resources with #{key}=#{value}", MU::WARN, details: resources if attempts > 1
- if attempts < 5
- attempts = attempts + 1
- sleep 15
- retry
- else
- raise e
- end
- end
- MU.log "Created tag #{key} with value #{value}", MU::DEBUG, details: resources
- else
- return {
- "Key" => key,
- "Value" => value
- }
- end
- end
-
@@azs = {}
# List the Availability Zones associated with a given Amazon Web Services
# region. If no region is given, search the one in which this MU master
# server resides.
# @param region [String]: The region to search.
# @return [Array<String>]: The Availability Zones in this region.
- def self.listAZs(region: MU.curRegion, account: nil, credentials: nil)
+ def self.listAZs(region: MU.curRegion, credentials: nil)
cfg = credConfig(credentials)
return [] if !cfg
if !region.nil? and @@azs[region]
return @@azs[region]
end
@@ -489,11 +460,36 @@
# the +account_number+ in which it's resident. If this is not applicable,
# such as for a {Habitat} or {Folder}, returns nil.
# @param cloudobj [MU::Cloud::AWS]: The resource from which to extract the habitat id
# @return [String,nil]
def self.habitat(cloudobj, nolookup: false, deploy: nil)
- cloudobj.respond_to?(:account_number) ? cloudobj.account_number : nil
+ @@habmap ||= {}
+# XXX whaddabout config['habitat'] HNNNGH
+
+ if cloudobj.respond_to?(:account_number) and cloudobj.account_number and
+ !cloudobj.account_number.empty?
+ return cloudobj.account_number
+ elsif cloudobj.config and cloudobj.config['account']
+ if nolookup
+ return cloudobj.config['account']
+ end
+ if @@habmap[cloudobj.config['account']]
+ return @@habmap[cloudobj.config['account']]
+ end
+ deploy ||= cloudobj.deploy if cloudobj.respond_to?(:deploy)
+
+ MU.log "Incomplete implementation: MU::Cloud::AWS.habitat", MU::DEBUG, details: deploy
+
+# accountobj = accountLookup(cloudobj.config['account'], deploy, raise_on_fail: false)
+
+# if accountobj
+# @@habmap[cloudobj.config['account']] = accountobj.cloud_id
+# return accountobj.cloud_id
+# end
+ end
+
+ nil
end
@@my_acct_num = nil
@@my_hosted_cfg = nil
@@ -504,11 +500,10 @@
def self.credToAcct(name = nil)
creds = credConfig(name)
return creds['account_number'] if creds['account_number']
- user_list = MU::Cloud::AWS.iam(credentials: name).list_users.users
acct_num = MU::Cloud::AWS.iam(credentials: name).list_users.users.first.arn.split(/:/)[4]
acct_num.to_s
end
# Return the name strings of all known sets of credentials for this cloud
@@ -541,12 +536,12 @@
end
}
if !found
MU.log "Attempting to create log bucket #{cfg['log_bucket_name']} for credentials #{credentials}", MU::WARN
begin
- resp = MU::Cloud::AWS.s3(credentials: credentials).create_bucket(bucket: cfg['log_bucket_name'], acl: "private")
- rescue Aws::S3::Errors::BucketAlreadyExists => e
+ MU::Cloud::AWS.s3(credentials: credentials).create_bucket(bucket: cfg['log_bucket_name'], acl: "private")
+ rescue Aws::S3::Errors::BucketAlreadyExists
raise MuError, "AWS credentials #{credentials} need a log bucket, and the name #{cfg['log_bucket_name']} is unavailable. Use mu-configure to edit credentials '#{credentials}' or 'hostname'"
end
end
cfg['log_bucket_name']
@@ -618,13 +613,13 @@
}
# Check each credential sets' resident account, then
$MU_CFG['aws'].each_pair { |acctname, cfg|
begin
- user_list = MU::Cloud::AWS.iam(credentials: acctname).list_users.users
+ MU::Cloud::AWS.iam(credentials: acctname).list_users.users
# rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
- rescue Exception => e
+ rescue StandardError => e
MU.log e.inspect, MU::WARN, details: cfg
next
end
acct_num = MU::Cloud::AWS.iam(credentials: acctname).list_users.users.first.arn.split(/:/)[4]
if acct_num.to_s == name.to_s
@@ -651,11 +646,11 @@
# XXX take optional credential set argument
# begin
# user_list = MU::Cloud::AWS.iam(region: credConfig['region']).list_users.users
## rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
-# rescue Exception => e
+# rescue StandardError => e
# MU.log "Got #{e.inspect} while trying to figure out our account number", MU::WARN, details: caller
# end
# if user_list.nil? or user_list.size == 0
resp = MU::Cloud::AWS.getAWSMetaData("network/interfaces/macs/")
return nil if !resp
@@ -680,11 +675,10 @@
def self.listRegions(us_only = false, credentials: nil)
if @@regions.size == 0
return [] if credConfig.nil?
result = MU::Cloud::AWS.ec2(region: myRegion, credentials: credentials).describe_regions.regions
- regions = []
@@regions_semaphore.synchronize {
begin
result.each { |r|
@@regions[r.region_name] = Proc.new {
listAZs(region: r.region_name, credentials: credentials)
@@ -1152,10 +1146,59 @@
logger.log "Failed metadata request #{base_url}/#{param}: #{e.inspect}", MU::DEBUG
return nil
end
end
+ # Tag a resource. Defaults to applying our MU deployment identifier, if no
+ # arguments other than the resource identifier are given.
+ # XXX this belongs in the cloud layer(s)
+ #
+ # @param resource [String]: The cloud provider identifier of the resource to tag
+ # @param tag_name [String]: The name of the tag to create
+ # @param tag_value [String]: The value of the tag
+ # @param region [String]: The cloud provider region
+ # @return [void]
+ def self.createTag(resource = nil,
+ tag_name="MU-ID",
+ tag_value=MU.deploy_id,
+ region: MU.curRegion,
+ credentials: nil)
+ attempts = 0
+
+ return nil if resource.nil?
+ resource = [resource] if resource.is_a?(String)
+
+ if !MU::Cloud::CloudFormation.emitCloudFormation
+ begin
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).create_tags(
+ resources: resource,
+ tags: [
+ {
+ key: tag_name,
+ value: tag_value
+ }
+ ]
+ )
+ rescue Aws::EC2::Errors::ServiceError => e
+ MU.log "Got #{e.inspect} tagging #{resource} with #{tag_name}=#{tag_value}", MU::WARN if attempts > 1
+ if attempts < 5
+ attempts = attempts + 1
+ sleep 15
+ retry
+ else
+ raise e
+ end
+ end
+ MU.log "Created tag #{tag_name} with value #{tag_value} for resource #{resource}", MU::DEBUG
+ else
+ return {
+ "Key" => tag_name,
+ "Value" => tag_value
+ }
+ end
+ end
+
@syslog_port_semaphore = Mutex.new
# Punch AWS security group holes for client nodes to talk back to us, the
# Mu Master, if we're in AWS.
# @return [void]
def self.openFirewallForClients
@@ -1203,12 +1246,12 @@
description: my_client_sg_name,
vpc_id: MU.myCloudDescriptor.vpc_id
)
sg_id = group.group_id
my_sgs << sg_id
- MU::MommaCat.createTag sg_id, "Name", my_client_sg_name
- MU::MommaCat.createTag sg_id, "MU-MASTER-IP", MU.mu_public_ip
+ MU::Cloud::AWS.createTag sg_id, "Name", my_client_sg_name
+ MU::Cloud::AWS.createTag sg_id, "MU-MASTER-IP", MU.mu_public_ip
MU::Cloud::AWS.ec2.modify_instance_attribute(
instance_id: my_instance_id,
groups: my_sgs
)
end
@@ -1235,11 +1278,11 @@
rescue NoMethodError
MU.log "Using AWS Security Group #{sg_id}"
end
allow_ips = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
- MU::MommaCat.listAllNodes.each_pair { |node, data|
+ MU::MommaCat.listAllNodes.values.each { |data|
next if data.nil? or !data.is_a?(Hash)
["public_ip_address"].each { |key|
if data.has_key?(key) and !data[key].nil? and !data[key].empty?
allow_ips << data[key] + "/32"
end
@@ -1264,11 +1307,11 @@
to_port: port,
ip_ranges: MU.structToHash(rule.ip_ranges)
}
]
)
- rescue Aws::EC2::Errors::InvalidPermissionNotFound => e
+ rescue Aws::EC2::Errors::InvalidPermissionNotFound
MU.log "Permission disappeared from #{sg_id} (port #{port.to_s}) before I could remove it", MU::WARN, details: MU.structToHash(rule.ip_ranges)
end
end
}
rescue NoMethodError
@@ -1298,12 +1341,10 @@
end
}
}
end
- private
-
# XXX we shouldn't have to do this, but AWS does not provide a way to look
# it up, and the pricing API only returns the human-readable strings.
@@regionLookup = {
"us-east-1" => "US East (N. Virginia)",
"us-east-2" => "US East (Ohio)",
@@ -1395,10 +1436,10 @@
# raise MuError, "Exhausted retries after #{retries} attempts while calling EC2's #{method_sym} in #{@region}. Args were: #{arguments}"
end
MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}, waiting #{interval.to_s}s and retrying. Args were: #{arguments}", debuglevel, details: caller
sleep interval
retry
- rescue Exception => e
+ rescue StandardError => e
MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}", MU::DEBUG, details: arguments
raise e
end
end
end