awx 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a22d18dbf189673739f5963a622151a85e814a1e
4
- data.tar.gz: 8b61eee5e62db727d1c105df70588e2fa0209434
3
+ metadata.gz: f9b808a6cbb91894ebd76305daa497467f62018a
4
+ data.tar.gz: 368253cb9c5c47013181e6e570b5ce216bf124b9
5
5
  SHA512:
6
- metadata.gz: 21cc5951d290166128b6eaa29b25de3ed4206744625013c2e420996827b47a7bfdfef276a0c5e2dffdba822e2ee353e95ba1115490c895099e29af3a34ace8fa
7
- data.tar.gz: c9723e5ca2518609c52228387e2886ae85a272beed50a9392acd8953b8aa0972452a861ee5f931820fabe25ca39106e4ba0f5ecd39893ba93706dd3ec1cf238c
6
+ metadata.gz: ff832f18916908040ef981c4f6823feeb0c33f7625d61d212036911a064ddfa453da307ab51491ce6e9ddab1f0cdfa8eda24636315bb45f3f9134cb41d43acc0
7
+ data.tar.gz: 90bef958997255122411c66e1801e8cf0300c85625750d8af6a921f3b3161d9cd97f1199637625cac3449de5176db8a9703dd0d31356eb61e31afb1a55bc569a
data/lib/aws/aws.rb ADDED
@@ -0,0 +1,9 @@
1
+ module App
2
+
3
+ class AWS
4
+
5
+ VALID_REGIONS = %w(ap-south-1 eu-west-3 eu-west-2 eu-west-1 ap-northeast-2 ap-northeast-1 sa-east-1 ca-central-1 ap-southeast-1 ap-southeast-2 eu-central-1 us-east-1 us-east-2 us-west-1 us-west-2)
6
+
7
+ end
8
+
9
+ end
data/lib/aws/aws_cli.rb CHANGED
@@ -65,40 +65,48 @@ module App
65
65
  end
66
66
 
67
67
  # Create a CloudFormation Stack.
68
- # @return Hash
69
- def self.cloudformation_stack_create(region, stack_name, s3_url, params: nil, tags: nil, capabilities: [])
68
+ # @return string (StackID)
69
+ def self.cloudformation_stack_create(region, stack_name, s3_url, params: nil, tags: nil, capabilities: [], term_protect: false, term_script: false, timeout: nil)
70
70
  params = params.nil? ? '' : " --parameters '#{params.gsub("'", "\\'")}'"
71
71
  tags = tags.nil? ? '' : " --tags '#{tags.gsub("'", "\\'")}'"
72
72
  capabilities = !capabilities.any? ? '' : " --capabilities #{capabilities.join(' ')}"
73
- command = "cloudformation create-stack --stack-name #{stack_name} --template-url #{s3_url}#{params}#{tags}#{capabilities}"
74
- stack_send = execute_as_proc("Sending CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", command, region, json: true)
73
+ term_protect = term_protect ? ' --enable-termination-protection' : ' --no-enable-termination-protection'
74
+ timeout = timeout.nil? ? '' : " --timeout-in-minutes #{timeout}"
75
+ command = "cloudformation create-stack --stack-name #{stack_name} --template-url #{s3_url}#{params}#{tags}#{capabilities}#{term_protect}#{timeout}"
76
+ App::AWSOutputter::output_cli_command("aws #{command} --region #{region} --profile #{App::AWSProfile::get_profile_name}")
77
+ puts
78
+ stack_send = execute_as_proc("Sending CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", command, region, json: true)
75
79
  begin
76
80
  if stack_send.has_key?('StackId')
77
- Blufin::Terminal::success('Template was accepted by AWS.', "\x1B[38;5;240mStackId \xe2\x80\x94 \x1B[38;5;40m#{stack_send['StackId']}")
78
- system("/usr/bin/open -a '/Applications/Google Chrome.app' https://#{region}.console.aws.amazon.com/cloudformation/home?region=#{region}#/stack/detail?stackId=#{URI::encode(stack_send['StackId'])}")
81
+ Blufin::Terminal::success('Template was accepted by AWS.', ["\x1B[38;5;240mStackId \xe2\x80\x94 \x1B[38;5;40m#{stack_send['StackId']}"])
82
+ stack_url = "https://#{region}.console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks?filter=active&tab=events&stackId=#{URI::encode(stack_send['StackId'])}"
83
+ system("/usr/bin/open -a '/Applications/Google Chrome.app' '#{stack_url}'")
79
84
  else
80
85
  Blufin::Terminal::error("Key not found in response: #{Blufin::Terminal::format_invalid('StackId')}", stack_send.inspect, true)
81
86
  end
82
87
  rescue
83
88
  Blufin::Terminal::error('Stack was not accepted by AWS.', App::AWSCli::format_cli_error(stack_send), true)
84
89
  end
85
- stack_complete = execute_as_proc("Creating CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation wait stack-create-complete --stack-name #{stack_name}", region, json: true)
86
- if stack_complete.to_s.strip == ''
87
- puts
88
- puts " \x1B[38;5;40mCREATE_COMPLETE\x1B[0m"
89
- puts
90
- stack_details = execute_as_proc("Getting CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation describe-stacks --stack-name #{stack_name}", region, json: true)
91
- begin
92
- stack_json = JSON.parse(stack_details.to_json)
93
- raise RuntimeError, 'Not a Hash' unless stack_json.is_a?(Hash)
90
+ unless term_script
91
+ stack_complete = execute_as_proc("Creating CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation wait stack-create-complete --stack-name #{stack_name}", region, json: true)
92
+ if stack_complete.to_s.strip == ''
93
+ puts
94
+ puts " \x1B[38;5;40mCREATE_COMPLETE\x1B[0m"
94
95
  puts
95
- Blufin::Terminal::code_highlight(stack_json.to_yaml, 'yml', 4)
96
- rescue
97
- Blufin::Terminal::error('It seems you Stack was created (but then something went wrong).', stack_details.inspect, false)
96
+ stack_details = execute_as_proc("Getting CloudFormation Stack: #{Blufin::Terminal::format_highlight(stack_name)}", "cloudformation describe-stacks --stack-name #{stack_name}", region, json: true)
97
+ begin
98
+ stack_json = JSON.parse(stack_details.to_json)
99
+ raise RuntimeError, 'Not a Hash' unless stack_json.is_a?(Hash)
100
+ puts
101
+ Blufin::Terminal::code_highlight(stack_json.to_yaml, 'yml', 4)
102
+ rescue
103
+ Blufin::Terminal::error('It seems you Stack was created (but then something went wrong).', stack_details.inspect, false)
104
+ end
105
+ else
106
+ Blufin::Terminal::error("Something went wrong. Go to: #{Blufin::Terminal::format_highlight("https://#{region}.console.aws.amazon.com/cloudformation/home")} to see what happened.", format_cli_error(stack_complete.to_s), true)
98
107
  end
99
- else
100
- Blufin::Terminal::error("Something went wrong. Go to: #{Blufin::Terminal::format_highlight('https://us-west-2.console.aws.amazon.com/cloudformation/home')} to see what happened.", format_cli_error(stack_complete.to_s), true)
101
108
  end
109
+ stack_send['StackId']
102
110
  end
103
111
 
104
112
  # Use this when a common such as "aws do-something" returns an error (such as: Stack [cognito-public-pool-go-eat-local-albert] already exists).
@@ -122,12 +130,10 @@ module App
122
130
  raise RuntimeError, 'Must provide region.' if region.nil? || region.strip == ''
123
131
  raise RuntimeError, "Invalid region: #{region}" unless get_regions.include?(region) || region == REGION_SKIP
124
132
  begin
125
- region = region == REGION_SKIP ? '' : " --region #{region}"
126
- aws_credentials = App::AWSConfig.get_credentials(App::AWSConfig::AWS_PROFILE_ALBERT_CLI)
127
- region = aws_credentials.region if region.nil?
128
- puts "\x1B[38;5;70m$ \x1B[38;5;240maws #{command}#{region}\x1B[0m" if verbose
133
+ region = region == REGION_SKIP ? '' : " --region #{region}"
134
+ puts "\x1B[38;5;70m$ \x1B[38;5;240maws #{command}#{region} --profile #{App::AWSProfile::get_profile_name}\x1B[0m" if verbose
129
135
  if json
130
- result = `aws #{command}#{region} 2>/tmp/execute-output-aws`
136
+ result = `aws #{command}#{region} --profile #{App::AWSProfile::get_profile_name} 2>/tmp/execute-output-aws`
131
137
  # If no JSON, simply return the output.
132
138
  return `cat /tmp/execute-output-aws` if result == ''
133
139
  begin
@@ -136,12 +142,12 @@ module App
136
142
  raise RuntimeError, "JSON Parsing Failed:\n\n#{e.message}"
137
143
  end
138
144
  else
139
- result = system("aws #{command}#{region} &>/dev/null")
140
- raise RuntimeError, 'This command this not return a status code of 0 (Success).' unless result
145
+ result = system("aws #{command}#{region} --profile #{App::AWSProfile::get_profile_name} 1>/dev/null 2>/tmp/execute-output-aws")
146
+ `cat /tmp/execute-output-aws` unless result
141
147
  return result
142
148
  end
143
149
  rescue => e
144
- Blufin::Terminal::error("Command Failed: #{Blufin::Terminal::format_command("aws #{command}#{region}")}", e.message, true)
150
+ Blufin::Terminal::error("Command Failed: #{Blufin::Terminal::format_command("aws #{command}#{region} --profile #{App::AWSProfile::get_profile_name}")}", e.message, true)
145
151
  end
146
152
  end
147
153
 
@@ -149,7 +155,7 @@ module App
149
155
  # Set JSON to TRUE if you expect JSON output back, otherwise return value will be boolean (TRUE if successful).
150
156
  # Highly recommended to keep verbose set to FALSE.
151
157
  # @return void
152
- def self.execute_as_proc(title, command, region, json: false, verbose: false, catch_exception: false)
158
+ def self.execute_as_proc(title, command, region, json: false, verbose: false)
153
159
  output = nil
154
160
  threads = []
155
161
  threads << Thread.new {
@@ -157,7 +163,7 @@ module App
157
163
  }
158
164
  sleep(0.1)
159
165
  puts if verbose
160
- Blufin::Terminal::execute_proc("AWS - #{title}", Proc.new { threads.each { |thread| thread.join } })
166
+ Blufin::Terminal::execute_proc("AWS \xe2\x80\x94 #{title}", Proc.new { threads.each { |thread| thread.join } })
161
167
  output
162
168
  end
163
169
 
@@ -2,15 +2,10 @@ module App
2
2
 
3
3
  class AWSCloudFormation
4
4
 
5
- S3_BUCKET_CLOUDFORMATION = 'blufin-cloudformation-templates'
6
- S3_BUCKET_CLOUDFORMATION_REGION = 'us-west-2'
7
- PATH_CLOUDFORMATION = 'aws-cloudformation'
8
- FILE_CLOUDFORMATION_DEFAULTS = 'cloudformation.rb'
9
-
10
5
  # Gets the path to the root of the cloudformation templates in blufin-secrets repo.
11
6
  # @return string
12
- def self.get_cloudformation_path(path = PATH_CLOUDFORMATION)
13
- path = "#{App::Config.param(ConfigUnique::PATH_TO_REPO_SECRETS)}/#{path}"
7
+ def self.get_cloudformation_path
8
+ path = App::AWSProfile::get_profile['CloudFormation']['TemplatePath']
14
9
  Blufin::Terminal::error("CloudFormation path not found: #{Blufin::Terminal::format_directory(path)}", 'This probably means directories got renamed or code got changed.', true) unless Blufin::Files::path_exists(path)
15
10
  path
16
11
  end
@@ -19,48 +14,76 @@ module App
19
14
  # Returns the S3 URL.
20
15
  # @return string
21
16
  def self.upload_cloudformation_template(template_category, template_name, description)
22
- source = "#{get_cloudformation_path}/#{template_category}/#{template_name}/template.yml"
17
+ source = "#{get_cloudformation_path}/#{template_category}/#{template_name}/template.yml"
18
+ tmp_file = "/tmp/aws-cf-upload-#{template_category}-#{template_name}-#{Blufin::Strings::random_string}.yml"
23
19
  raise RuntimeError, "File does not exist: #{source}" unless Blufin::Files::file_exists(source)
24
- yml_data = YAML.load_file(File.expand_path(source))
25
- yml_data['Description'] = description
26
- description_written = false
27
- new_yaml = {}
28
- yml_data.keys.each do |key|
29
- if %w(AWSTemplateFormatVersion).include?(key)
30
- new_yaml[key] = yml_data[key]
20
+ Blufin::Terminal::execute("cp #{source} #{tmp_file}", text: "Preparing template: \x1B[38;5;240m#{tmp_file}\x1B[0m")
21
+ # Add description to final YML file.
22
+ Blufin::Files::write_line_to_file(tmp_file, "Description: \"#{description.gsub('"', '\"')}\"", /AWSTemplateFormatVersion:\s*("|')?[0-9\-]+("|')?/i)
23
+ # This block of code removes the 2nd description tag.
24
+ new_lines = []
25
+ description_found = false
26
+ parsing_parameters = true
27
+ Blufin::Files::read_file(tmp_file).each do |line|
28
+ line = line.gsub("\n", '')
29
+ if line.strip =~ /^description:/i
30
+ new_lines << line unless description_found
31
+ description_found = true
31
32
  else
32
- unless description_written
33
- description_written = true
34
- new_yaml['Description'] = description
33
+ parsing_parameters = true if line.strip =~ /^parameters:$/i
34
+ if parsing_parameters
35
+ # AWS Template Anatomy: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html
36
+ parsing_parameters = false if line.strip =~ /^(Metadata|Mappings|Conditions|Transform|Resources|Outputs)+:$/
37
+ # This skips all the parameter defaults (as they may contain weird data which won't pass regex validation when initially sent to AWS).
38
+ next if line.strip =~ /^default:/i && parsing_parameters
35
39
  end
36
- new_yaml[key] = yml_data[key] unless key == 'Description'
40
+ new_lines << line
37
41
  end
38
42
  end
39
- tmp_file = "/tmp/aws-cf-upload-#{template_category}-#{template_name}.yml"
40
- Blufin::Files::write_file(tmp_file, convert_string_to_line_array(new_yaml.to_yaml))
41
- App::AWSCli::s3_upload(tmp_file, S3_BUCKET_CLOUDFORMATION, get_template_filename(template_category, template_name))
43
+ Blufin::Files::write_file(tmp_file, new_lines)
44
+ template_filename = "#{template_category}-#{template_name}-#{DateTime.now.strftime('%Y%m%d-%H%M%S')}.yml"
45
+ bucket_path = get_s3_bucket_path
46
+ bucket_path = bucket_path == '' ? '' : "#{bucket_path}/"
47
+ App::AWSCli::s3_upload(tmp_file, App::AWSProfile::get_profile['CloudFormation']['S3Bucket'], "#{bucket_path}#{template_filename}")
48
+ # Return the S3 bucket URL.
49
+ "#{get_s3_bucket_url}/#{template_filename}"
42
50
  end
43
51
 
44
- # Gets the S3 bucket URL.
52
+ # Returns S3 bucket URL based on config parameters.
45
53
  # @return string
46
- def self.get_cloudformation_s3_bucket_url(template_category, template_name)
47
- "https://#{S3_BUCKET_CLOUDFORMATION}.s3-#{S3_BUCKET_CLOUDFORMATION_REGION}.amazonaws.com/#{get_template_filename(template_category, template_name)}"
54
+ def self.get_s3_bucket_url
55
+ bucket_path = get_s3_bucket_path
56
+ bucket_path = bucket_path == '' ? '' : "/#{bucket_path}"
57
+ "https://#{App::AWSProfile::get_profile['CloudFormation']['S3Bucket']}.s3-#{App::AWSProfile::get_profile['CloudFormation']['S3BucketRegion']}.amazonaws.com#{bucket_path}"
48
58
  end
49
59
 
50
- # Converts cognito/private-pool to -> cognito-private-pool.yml
60
+ # Returns the S3 bucket path based on config parameters.
51
61
  # @return string
52
- def self.get_template_filename(template_category, template_name)
53
- "#{template_category}-#{template_name}.yml"
62
+ def self.get_s3_bucket_path
63
+ bucket_path = App::AWSProfile::get_profile['CloudFormation']['S3BucketPath']
64
+ bucket_path.nil? || bucket_path.to_s.strip == '' ? '' : bucket_path
54
65
  end
55
66
 
56
- # Converts a string to an Array of lines to a string.
57
- # @return String
58
- # TODO - Must move Blufin::YmlCommon from blufin -> blufin-lib. Not sure what the damage will be... 07/08/2019.
59
- def self.convert_string_to_line_array(string)
60
- raise RuntimeError, "Expected String, instead got: #{string.class}" unless string.is_a?(String)
61
- array_of_lines = []
62
- string.split("\n").each { |line| array_of_lines << line.gsub("\n", '') }
63
- array_of_lines
67
+ # Returns an array of cloudformation stack-names.
68
+ # @return Array of Hashes
69
+ def self.get_stacks
70
+ results = []
71
+ json = Blufin::Terminal::execute('awx l -r CloudFormationStacks -j', capture: true, text: "AWS \xe2\x80\x94 Getting CloudFormation Stacks...")
72
+ begin
73
+ data = JSON.parse(json)
74
+ rescue => e
75
+ puts
76
+ puts json
77
+ Blufin::Terminal::error('Failed to parse AWS response JSON.', e.message)
78
+ end
79
+ data.each do |stack|
80
+ results << {
81
+ :name => stack['StackName'],
82
+ :region => stack['region']
83
+ }
84
+ end
85
+ results.sort_by! { |hsh| hsh[:name] }
86
+ results
64
87
  end
65
88
 
66
89
  end
@@ -91,7 +91,7 @@ module App
91
91
  column('Max-L', :width => column_short, :color => HEADER_COLOR)
92
92
  column('Min-V', :width => column_short, :color => HEADER_COLOR)
93
93
  column('Max-V', :width => column_short, :color => HEADER_COLOR)
94
- column('Cached Value(s)', :width => remaining, :color => HEADER_COLOR)
94
+ column('Cached/Default Value(s)', :width => remaining, :color => HEADER_COLOR)
95
95
  column('', :width => 2, :color => HEADER_COLOR)
96
96
  end
97
97
  row do
@@ -109,7 +109,13 @@ module App
109
109
  mav = data[:max_value]
110
110
  cop = 'light-green'
111
111
  cop = 'purple' if data[:type_internal] == :autocomplete
112
- cop = 'yellow' if data[:type_internal] == :system || [AppCommand::AWSCloudFormationCreate::OPTION_STACK_NAME, AppCommand::AWSCloudFormationCreate::OPTION_DESCRIPTION].include?(data[:parameter])
112
+ cop = 'light-grey' if data[:type_internal] == :system || [
113
+ AppCommand::AWSCloudFormationCreate::OPTION_STACK_NAME,
114
+ AppCommand::AWSCloudFormationCreate::OPTION_PROJECT_ID,
115
+ AppCommand::AWSCloudFormationCreate::OPTION_DESCRIPTION,
116
+ AppCommand::AWSCloudFormationCreate::OPTION_TERM_PROTECT,
117
+ AppCommand::AWSCloudFormationCreate::OPTION_TIMEOUT
118
+ ].include?(data[:parameter])
113
119
  # In case you want to change color in future, currently this is redundant.
114
120
  cod = data[:type_internal] == :system ? 'default' : 'default'
115
121
  cot = data[:type_internal] == :system ? 'default' : 'default'
@@ -152,10 +158,15 @@ module App
152
158
  # @return void
153
159
  def self.get_formatter(key = nil, resource: nil, color: 'default')
154
160
  formatters = {
161
+ 'cloudformation-stack' => Proc.new { |n|
162
+ [n.gsub(/^arn:aws:cloudformation:[a-z]{2}-[a-z]{2,12}-\d+\D?:\d{10,14}:stack\//, ''), color]
163
+ },
155
164
  'cloudfront-status' => Proc.new { |n|
156
165
  case n
157
166
  when 'Deployed'
158
167
  color = 'green'
168
+ when 'InProgress'
169
+ color = 'orange'
159
170
  else
160
171
  Blufin::Terminal::output("Add something to aws_outputter switch statement for: #{n}", Blufin::Terminal::MSG_TODO)
161
172
  color = 'default'
@@ -188,6 +199,7 @@ module App
188
199
  color = 'dark-grey'
189
200
  when 'terminated'
190
201
  color = 'red'
202
+
191
203
  else
192
204
  Blufin::Terminal::output("Add something to aws_outputter switch statement for: #{n}", Blufin::Terminal::MSG_TODO)
193
205
  color = 'default'
@@ -203,11 +215,15 @@ module App
203
215
  region = n.ljust(10, ' ')
204
216
  [region, region_color]
205
217
  },
218
+ 'route-53-domain-name' => Proc.new { |n|
219
+ [n.gsub(/\.$/, ''), color]
220
+ },
206
221
  'route-53-hosted-zone-id' => Proc.new { |n|
207
222
  zone_color = color
208
223
  ns = n.split('/')
209
224
  [ns[ns.length - 1], zone_color]
210
225
  },
226
+
211
227
  }
212
228
  raise RuntimeError, "Key not found: #{key}" unless key.nil? || formatters.has_key?(key)
213
229
  return formatters.keys if key.nil?
@@ -242,6 +258,21 @@ module App
242
258
  (width == '*') ? wildcard_width : width
243
259
  end
244
260
 
261
+ # Standardized way of outputting a command.
262
+ # @return void
263
+ def self.output_cli_command(command, path = nil)
264
+ puts " \x1B[38;5;70m$ \x1B[38;5;240m#{command}\x1B[0m" if path.nil?
265
+ puts " \x1B[38;5;70m$ \x1B[38;5;240m#{command} [\x1B[38;5;246m#{path}\x1B[240m]\x1B[0m" unless path.nil?
266
+ end
267
+
268
+ # Standardized way of rendering selection output.
269
+ # @return string
270
+ def self.render_selection(primary, secondary = nil, tertiary = nil)
271
+ return "#{Blufin::Terminal::format_action(primary)} \x1B[38;5;240m[#{Blufin::Terminal::format_highlight(secondary)}\x1B[38;5;240m]\x1B[38;5;240m[#{Blufin::Terminal::format_highlight(tertiary)}\x1B[38;5;240m]" if !tertiary.nil? && !secondary.nil?
272
+ return "#{Blufin::Terminal::format_action(primary)} \x1B[38;5;240m[#{Blufin::Terminal::format_highlight(secondary)}\x1B[38;5;240m]" unless secondary.nil?
273
+ return "#{Blufin::Terminal::format_action(primary)}" if secondary.nil?
274
+ end
275
+
245
276
  end
246
277
 
247
278
  end
@@ -0,0 +1,116 @@
1
+ module App
2
+
3
+ class AWSProfile
4
+
5
+ @@profiles = nil
6
+ @@profile = nil
7
+ @@credentials = nil
8
+
9
+ FILE_AWS_CONFIG = File.expand_path('~/.aws/config')
10
+ FILE_AWS_CREDENTIALS = File.expand_path('~/.aws/credentials')
11
+ PROFILE_DEFAULT = 'DefaultProfile'
12
+ PROFILE = 'Profile'
13
+ PROFILES = 'Profiles'
14
+ CLOUDFORMATION = 'CloudFormation'
15
+
16
+ # Reads the config data and decides what profile to use.
17
+ # @return void
18
+ def self.init(config_data)
19
+
20
+ raise RuntimeError, 'Cannot run App::AWSProfile::init more than once.' unless @@profiles.nil? && @@profile.nil? && @@credentials.nil?
21
+
22
+ @@profiles = {}
23
+ @@profile = {}
24
+
25
+ first_key = nil
26
+
27
+ # Put all the profiles in a global Hash.
28
+ config_data[PROFILES].each do |profile|
29
+ first_key = profile[PROFILE] if first_key.nil?
30
+ @@profiles[profile[PROFILE]] = profile
31
+ end
32
+
33
+ if @@profiles.length == 1
34
+ @@profile = @@profiles[first_key]
35
+ elsif @@profiles.length > 1
36
+ if config_data[PROFILE_DEFAULT].nil?
37
+ Blufin::Terminal::error('No default profile found.', "When more than 1 profile is specified, you must also specify a #{Blufin::Terminal::format_highlight('DefaultProfile:')}", true)
38
+ elsif !@@profiles.keys.include?(config_data[PROFILE_DEFAULT])
39
+ Blufin::Terminal::error("Invalid profile: #{Blufin::Terminal::format_invalid(config_data[PROFILE_DEFAULT])}. Available profiles are:", @@profiles.keys, true)
40
+ else
41
+ @@profile = @@profiles[config_data[PROFILE_DEFAULT]]
42
+ end
43
+ else
44
+ raise RuntimeError, 'No profiles found.'
45
+ end
46
+
47
+ errors = []
48
+
49
+ # Validate CloudFormation data (if exists)
50
+ if @@profile.has_key?(CLOUDFORMATION)
51
+ cloudformation_template_path = @@profile[CLOUDFORMATION]['TemplatePath']
52
+ s3_region = @@profile[CLOUDFORMATION]['S3BucketRegion']
53
+ default_regions = @@profile[CLOUDFORMATION]['Defaults']['Regions']
54
+ errors << "Path not found: #{Blufin::Terminal::format_invalid(cloudformation_template_path)}" unless Blufin::Files::path_exists(cloudformation_template_path)
55
+ errors << "Invalid region: #{Blufin::Terminal::format_invalid(s3_region)}" unless App::AWS::VALID_REGIONS.include?(s3_region)
56
+ errors << "Need atleast 1 default region for: #{Blufin::Terminal::format_invalid('Profiles[].CloudFormation.Defaults.Regions')}" if default_regions.nil? || !default_regions.any?
57
+ default_regions.each do |default_region|
58
+ errors << "Invalid region: #{Blufin::Terminal::format_invalid(default_region)}" unless App::AWS::VALID_REGIONS.include?(default_region)
59
+ end
60
+ end
61
+
62
+ # Check the credentials exist.
63
+ if Blufin::Files::file_exists(FILE_AWS_CREDENTIALS)
64
+ @@aws_credentials = App::AWSCredentials.new
65
+ profile = @@profile[PROFILE]
66
+ config = Blufin::Files::file_exists(FILE_AWS_CONFIG) ? ParseConfig.new(FILE_AWS_CONFIG) : nil
67
+ credentials = ParseConfig.new(FILE_AWS_CREDENTIALS)
68
+ unless credentials.params[profile].nil?
69
+ # Currently not used/required (but here just in case).
70
+ unless config.nil? || config.params[profile].nil?
71
+ @@aws_credentials.region = config.params[profile]['region'] unless config.params[profile]['region'].nil?
72
+ @@aws_credentials.output = config.params[profile]['output'] unless config.params[profile]['output'].nil?
73
+
74
+ end
75
+ @@aws_credentials.aws_key = credentials.params[profile]['aws_access_key_id'] unless credentials.params[profile]['aws_access_key_id'].nil?
76
+ @@aws_credentials.aws_secret = credentials.params[profile]['aws_secret_access_key'] unless credentials.params[profile]['aws_secret_access_key'].nil?
77
+ end
78
+ errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_access_key_id')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@aws_credentials.aws_key.nil?
79
+ errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_secret_access_key')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@aws_credentials.aws_secret.nil?
80
+ else
81
+ errors << "aws-cli error. Cannot find file: #{Blufin::Terminal::format_invalid(FILE_AWS_CREDENTIALS)}"
82
+ end
83
+
84
+ # If anything is wrong, output error(s).
85
+ Blufin::Config::invalid_configuration(App::GEM_NAME, errors) if errors.any?
86
+
87
+ end
88
+
89
+ # Gets the active profile.
90
+ # @return Hash
91
+ def self.get_profile
92
+ @@profile
93
+ end
94
+
95
+ # Convenience method to just get the profile name.
96
+ # @return string
97
+ def self.get_profile_name
98
+ @@profile[PROFILE]
99
+ end
100
+
101
+ # Returns an Array of all available profile names (not the entire profile).
102
+ # @return Array
103
+ def self.get_profile_names
104
+ @@profiles.keys
105
+ end
106
+
107
+ # Gets AWS credentials from ~/.aws directory for given profile.
108
+ # If credentials don't exist (or are missing information) -- nil is returned.
109
+ # @return App::AWSCredentials
110
+ def self.get_credentials
111
+ @@aws_credentials
112
+ end
113
+
114
+ end
115
+
116
+ end