knife-cfn 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ed956b7bf7624fb88560a3aec0e5bc243b8a0169
4
+ data.tar.gz: 770c634481f6a69b773fa4602c521f0633b3664b
5
+ SHA512:
6
+ metadata.gz: d307cc10dd135f22c375397678232228331ae59cb9429dffc3b0a346169a0c6e7cc74029942ae9f067906715beafeaa5905de0093fecea7a222a7f8ac67dd92b
7
+ data.tar.gz: 67be89dad9b22c72d132529c8baefaaa9cf430305125e0415405bc959c6918e155d6d409f6358b5464d5747da878c4edeb0085426d5b5c1728a0534f5f17210c
@@ -1,4 +1,8 @@
1
1
  #
2
+ # Author:: Seth Chisamore (<schisamo@chef.io>)
3
+ # Copyright:: Copyright (c) 2011-2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
2
6
  # Licensed under the Apache License, Version 2.0 (the "License");
3
7
  # you may not use this file except in compliance with the License.
4
8
  # You may obtain a copy of the License at
@@ -30,6 +34,17 @@ class Chef
30
34
  require 'chef/json_compat'
31
35
  end
32
36
 
37
+ option :aws_credential_file,
38
+ :long => "--aws-credential-file FILE",
39
+ :description => "File containing AWS credentials as used by aws cmdline tools",
40
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_credential_file] = key }
41
+
42
+ option :aws_profile,
43
+ :long => "--aws-profile PROFILE",
44
+ :description => "AWS profile, from credential file, to use",
45
+ :default => 'default',
46
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_profile] = key }
47
+
33
48
  option :aws_access_key_id,
34
49
  :short => "-A ID",
35
50
  :long => "--aws-access-key-id KEY",
@@ -42,27 +57,45 @@ class Chef
42
57
  :description => "Your AWS API Secret Access Key",
43
58
  :proc => Proc.new { |key| Chef::Config[:knife][:aws_secret_access_key] = key }
44
59
 
60
+ option :aws_session_token,
61
+ :long => "--aws-session-token TOKEN",
62
+ :description => "Your AWS Session Token, for use with AWS STS Federation or Session Tokens",
63
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_session_token] = key }
64
+
45
65
  option :region,
46
66
  :long => "--region REGION",
47
67
  :description => "Your AWS region",
48
- :default => "us-east-1",
49
68
  :proc => Proc.new { |key| Chef::Config[:knife][:region] = key }
69
+
70
+ option :use_iam_profile,
71
+ :long => "--use-iam-profile",
72
+ :description => "Use IAM profile assigned to current machine",
73
+ :boolean => true,
74
+ :default => false,
75
+ :proc => Proc.new { |key| Chef::Config[:knife][:use_iam_profile] = key }
50
76
  end
51
77
  end
52
78
 
53
79
  def connection
80
+ connection_settings = {
81
+ # :provider => 'AWS',
82
+ :region => locate_config_value(:region)
83
+ }
84
+ if locate_config_value(:use_iam_profile)
85
+ connection_settings[:use_iam_profile] = true
86
+ else
87
+ connection_settings[:aws_access_key_id] = locate_config_value(:aws_access_key_id)
88
+ connection_settings[:aws_secret_access_key] = locate_config_value(:aws_secret_access_key)
89
+ connection_settings[:aws_session_token] = locate_config_value(:aws_session_token)
90
+ end
54
91
  @connection ||= begin
55
- connection = Fog::AWS::CloudFormation.new(
56
- :aws_access_key_id => Chef::Config[:knife][:aws_access_key_id],
57
- :aws_secret_access_key => Chef::Config[:knife][:aws_secret_access_key],
58
- :region => locate_config_value(:region)
59
- )
92
+ connection = Fog::AWS::CloudFormation.new(connection_settings)
60
93
  end
61
94
  end
62
95
 
63
96
  def locate_config_value(key)
64
97
  key = key.to_sym
65
- Chef::Config[:knife][key] || config[key]
98
+ config[key] || Chef::Config[:knife][key]
66
99
  end
67
100
 
68
101
  def msg_pair(label, value, color=:cyan)
@@ -71,23 +104,75 @@ class Chef
71
104
  end
72
105
  end
73
106
 
107
+ def is_image_windows?
108
+ image_info = connection.images.get(@server.image_id)
109
+ return image_info.platform == 'windows'
110
+ end
111
+
74
112
  def validate!(keys=[:aws_access_key_id, :aws_secret_access_key])
75
113
  errors = []
76
114
 
77
- keys.each do |k|
78
- pretty_key = k.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
79
- if Chef::Config[:knife][k].nil?
80
- errors << "You did not provide a valid '#{pretty_key}' value."
115
+ unless locate_config_value(:use_iam_profile)
116
+ unless Chef::Config[:knife][:aws_credential_file].nil?
117
+ unless (Chef::Config[:knife].keys & [:aws_access_key_id, :aws_secret_access_key]).empty?
118
+ errors << "Either provide a credentials file or the access key and secret keys but not both."
119
+ end
120
+ # File format:
121
+ # AWSAccessKeyId=somethingsomethingdarkside
122
+ # AWSSecretKey=somethingsomethingcomplete
123
+ # OR
124
+ # [default]
125
+ # aws_access_key_id = somethingsomethingdarkside
126
+ # aws_secret_access_key = somethingsomethingdarkside
127
+
128
+ aws_creds = ini_parse(File.read(Chef::Config[:knife][:aws_credential_file]))
129
+ profile = Chef::Config[:knife][:aws_profile] || 'default'
130
+ entries = aws_creds.values.first.has_key?("AWSAccessKeyId") ? aws_creds.values.first : aws_creds[profile]
131
+
132
+ Chef::Config[:knife][:aws_access_key_id] = entries['AWSAccessKeyId'] || entries['aws_access_key_id']
133
+ Chef::Config[:knife][:aws_secret_access_key] = entries['AWSSecretKey'] || entries['aws_secret_access_key']
134
+ end
135
+
136
+ keys.each do |k|
137
+ pretty_key = k.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
138
+ if Chef::Config[:knife][k].nil?
139
+ errors << "You did not provide a valid '#{pretty_key}' value."
140
+ end
81
141
  end
82
- end
83
142
 
84
- if errors.each{|e| ui.error(e)}.any?
85
- exit 1
143
+ if errors.each{|e| ui.error(e)}.any?
144
+ exit 1
145
+ end
86
146
  end
87
147
  end
88
148
 
89
149
  end
90
- end
91
- end
92
150
 
151
+ def iam_name_from_profile(profile)
152
+ # The IAM profile object only contains the name as part of the arn
153
+ if profile && profile.key?('arn')
154
+ name = profile['arn'].split('/')[-1]
155
+ end
156
+ name ||= ''
157
+ end
93
158
 
159
+ def ini_parse(file)
160
+ current_section = {}
161
+ map = {}
162
+ file.each_line do |line|
163
+ line = line.split(/^|\s;/).first # remove comments
164
+ section = line.match(/^\s*\[([^\[\]]+)\]\s*$/) unless line.nil?
165
+ if section
166
+ current_section = section[1]
167
+ elsif current_section
168
+ item = line.match(/^\s*(.+?)\s*=\s*(.+?)\s*$/) unless line.nil?
169
+ if item
170
+ map[current_section] ||= {}
171
+ map[current_section][item[1]] = item[2]
172
+ end
173
+ end
174
+ end
175
+ map
176
+ end
177
+ end
178
+ end
@@ -1,125 +1,125 @@
1
- #
2
- # Licensed under the Apache License, Version 2.0 (the "License");
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an "AS IS" BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- #
14
-
15
- require 'chef/knife'
16
- require 'chef/knife/cfn_base'
17
-
18
- class Chef
19
- class Knife
20
- class CfnCreate < Chef::Knife::CfnBase
21
-
22
- deps do
23
- require 'fog'
24
- require 'readline'
25
- require 'chef/json_compat'
26
- require 'chef/knife/bootstrap'
27
- Chef::Knife::Bootstrap.load_deps
28
- end
29
-
30
- banner "knife cfn create <stack name> (options)"
31
-
32
- option :capabilities,
33
- :short => "-C CAPABILITY..",
34
- :long => "--capabilities CAPABILITY1,CAPABILITY2,CAPABILITY3..",
35
- :description => "The explicitly approved capabilities that may be used during this stack creation",
36
- :proc => Proc.new { |capabilities| capabilities.split(',') }
37
-
38
- option :disable_rollback,
39
- :short => "-d",
40
- :long => "--disable-rollback",
41
- :description => "Flag to disable rollback of created resources when failures are encountered during stack creation. The default value is 'false'",
42
- :proc => Proc.new { |d| Chef::Config[:knife][:disable_rollback] = "true" }
43
-
44
- option :template_file,
45
- :short => "-f TEMPLATE_FILE",
46
- :long => "--template-file TEMPLATE_FILE",
47
- :description => "Path to the file that contains the template",
48
- :proc => Proc.new { |f| Chef::Config[:knife][:template_file] = f }
49
-
50
- option :notification_arns,
51
- :short => "-n NOTIFICATION_ARN1,NOTIFICATION_ARN2,NOTIFICATION_ARN3..",
52
- :long => "--notification-arns VALUE1,VALUE2,VALUE3..",
53
- :description => "SNS ARNs to receive notification about the stack",
54
- :proc => Proc.new { |notification_arns| notification_arns.split(',') }
55
-
56
- option :parameters,
57
- :short => "-p 'key1=value1;key2=value2...'",
58
- :long => "--parameters 'key1=value1;key2=value2...'",
59
- :description => "Parameter values used to create the stack",
60
- :proc => Proc.new { |parameters| parameters.split(';') }
61
-
62
- option :timeout,
63
- :short => "-t TIMEOUT_VALUE",
64
- :long => "--timeout TIMEOUT_VALUE",
65
- :description => " Stack creation timeout in minutes",
66
- :proc => Proc.new { |t| Chef::Config[:knife][:timeout] = t }
67
-
68
- option :template_url,
69
- :short => "-u TEMPLATE_URL",
70
- :long => "--template-file TEMPLATE_URL",
71
- :description => "Path of the URL that contains the template. This must be a reference to a template in an S3 bucket in the same region that the stack will be created in",
72
- :proc => Proc.new { |u| Chef::Config[:knife][:template_url] = u }
73
-
74
- def run
75
- $stdout.sync = true
76
-
77
- validate!
78
-
79
- stack_name = @name_args[0]
80
-
81
- if stack_name.nil?
82
- show_usage
83
- ui.error("You must specify a stack name")
84
- exit 1
85
- end
86
-
87
- begin
88
- response = connection.create_stack(stack_name, create_create_def)
89
- rescue Excon::Errors::BadRequest => e
90
- i= e.response.body.index("<Message>")
91
- j = e.response.body.index("</Message>")
92
- if !i.nil? and !j.nil?
93
- ui.error(e.response.body[i+9,j-i-9])
94
- else
95
- print "\n#{e.response.body}"
96
- end
97
- exit 1
98
- else
99
- message = "Stack #{stack_name} creation started"
100
- print "\n#{ui.color(message, :green)}\n"
101
- end
102
- end
103
- end
104
-
105
- def create_create_def
106
- create_def = {}
107
- template_file = locate_config_value(:template_file)
108
- if template_file != nil and template_file != ""
109
- doc = File.open(template_file, 'rb') { |file| file.read }
110
- create_def['TemplateBody'] = doc
111
- end
112
- create_def['TemplateURL'] = locate_config_value(:template_url)
113
- create_def['Capabilities'] = locate_config_value(:capabilities)
114
- create_def['DisableRollback'] = locate_config_value(:disable_rollback)
115
- create_def['NotificationARNs'] = locate_config_value(:notification_arns)
116
- hashed_parameters={}
117
- parameters = locate_config_value(:parameters)
118
- parameters.map{ |t| key,val=t.split('='); hashed_parameters[key]=val} unless parameters.nil?
119
- create_def['Parameters'] = hashed_parameters
120
- create_def['TimeoutInMinutes'] = locate_config_value(:timeout)
121
- create_def
122
- end
123
-
124
- end
125
- end
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require 'chef/knife'
16
+ require 'chef/knife/cfn_base'
17
+
18
+ class Chef
19
+ class Knife
20
+ class CfnCreate < Chef::Knife::CfnBase
21
+
22
+ deps do
23
+ require 'fog'
24
+ require 'readline'
25
+ require 'chef/json_compat'
26
+ require 'chef/knife/bootstrap'
27
+ Chef::Knife::Bootstrap.load_deps
28
+ end
29
+
30
+ banner "knife cfn create <stack name> (options)"
31
+
32
+ option :capabilities,
33
+ :short => "-C CAPABILITY..",
34
+ :long => "--capabilities CAPABILITY1,CAPABILITY2,CAPABILITY3..",
35
+ :description => "The explicitly approved capabilities that may be used during this stack creation",
36
+ :proc => Proc.new { |capabilities| capabilities.split(',') }
37
+
38
+ option :disable_rollback,
39
+ :short => "-d",
40
+ :long => "--disable-rollback",
41
+ :description => "Flag to disable rollback of created resources when failures are encountered during stack creation. The default value is 'false'",
42
+ :proc => Proc.new { |d| Chef::Config[:knife][:disable_rollback] = "true" }
43
+
44
+ option :template_file,
45
+ :short => "-f TEMPLATE_FILE",
46
+ :long => "--template-file TEMPLATE_FILE",
47
+ :description => "Path to the file that contains the template",
48
+ :proc => Proc.new { |f| Chef::Config[:knife][:template_file] = f }
49
+
50
+ option :notification_arns,
51
+ :short => "-n NOTIFICATION_ARN1,NOTIFICATION_ARN2,NOTIFICATION_ARN3..",
52
+ :long => "--notification-arns VALUE1,VALUE2,VALUE3..",
53
+ :description => "SNS ARNs to receive notification about the stack",
54
+ :proc => Proc.new { |notification_arns| notification_arns.split(',') }
55
+
56
+ option :parameters,
57
+ :short => "-p 'key1=value1;key2=value2...'",
58
+ :long => "--parameters 'key1=value1;key2=value2...'",
59
+ :description => "Parameter values used to create the stack",
60
+ :proc => Proc.new { |parameters| parameters.split(';') }
61
+
62
+ option :timeout,
63
+ :short => "-t TIMEOUT_VALUE",
64
+ :long => "--timeout TIMEOUT_VALUE",
65
+ :description => " Stack creation timeout in minutes",
66
+ :proc => Proc.new { |t| Chef::Config[:knife][:timeout] = t }
67
+
68
+ option :template_url,
69
+ :short => "-u TEMPLATE_URL",
70
+ :long => "--template-file TEMPLATE_URL",
71
+ :description => "Path of the URL that contains the template. This must be a reference to a template in an S3 bucket in the same region that the stack will be created in",
72
+ :proc => Proc.new { |u| Chef::Config[:knife][:template_url] = u }
73
+
74
+ def run
75
+ $stdout.sync = true
76
+
77
+ validate!
78
+
79
+ stack_name = @name_args[0]
80
+
81
+ if stack_name.nil?
82
+ show_usage
83
+ ui.error("You must specify a stack name")
84
+ exit 1
85
+ end
86
+
87
+ begin
88
+ response = connection.create_stack(stack_name, create_create_def)
89
+ rescue Excon::Errors::BadRequest => e
90
+ i= e.response.body.index("<Message>")
91
+ j = e.response.body.index("</Message>")
92
+ if !i.nil? and !j.nil?
93
+ ui.error(e.response.body[i+9,j-i-9])
94
+ else
95
+ print "\n#{e.response.body}"
96
+ end
97
+ exit 1
98
+ else
99
+ message = "Stack #{stack_name} creation started"
100
+ print "\n#{ui.color(message, :green)}\n"
101
+ end
102
+ end
103
+ end
104
+
105
+ def create_create_def
106
+ create_def = {}
107
+ template_file = locate_config_value(:template_file)
108
+ if template_file != nil and template_file != ""
109
+ doc = File.open(template_file, 'rb') { |file| file.read }
110
+ create_def['TemplateBody'] = doc
111
+ end
112
+ create_def['TemplateURL'] = locate_config_value(:template_url)
113
+ create_def['Capabilities'] = locate_config_value(:capabilities)
114
+ create_def['DisableRollback'] = locate_config_value(:disable_rollback)
115
+ create_def['NotificationARNs'] = locate_config_value(:notification_arns)
116
+ hashed_parameters={}
117
+ parameters = locate_config_value(:parameters)
118
+ parameters.map{ |t| key,val=t.split('='); hashed_parameters[key]=val} unless parameters.nil?
119
+ create_def['Parameters'] = hashed_parameters
120
+ create_def['TimeoutInMinutes'] = locate_config_value(:timeout)
121
+ create_def
122
+ end
123
+
124
+ end
125
+ end
@@ -26,28 +26,68 @@ class Chef
26
26
  require 'chef/knife/bootstrap'
27
27
  Chef::Knife::Bootstrap.load_deps
28
28
  end
29
-
29
+
30
30
  banner "knife cfn delete <stack name>"
31
-
31
+
32
+ option :aws_credential_file,
33
+ :long => "--aws-credential-file FILE",
34
+ :description => "File containing AWS credentials as used by aws cmdline tools",
35
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_credential_file] = key }
36
+
37
+ option :aws_profile,
38
+ :long => "--aws-profile PROFILE",
39
+ :description => "AWS profile, from credential file, to use",
40
+ :default => 'default',
41
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_profile] = key }
42
+
43
+ option :aws_access_key_id,
44
+ :short => "-A ID",
45
+ :long => "--aws-access-key-id KEY",
46
+ :description => "Your AWS Access Key ID",
47
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_access_key_id] = key }
48
+
49
+ option :aws_secret_access_key,
50
+ :short => "-K SECRET",
51
+ :long => "--aws-secret-access-key SECRET",
52
+ :description => "Your AWS API Secret Access Key",
53
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_secret_access_key] = key }
54
+
55
+ option :aws_session_token,
56
+ :long => "--aws-session-token TOKEN",
57
+ :description => "Your AWS Session Token, for use with AWS STS Federation or Session Tokens",
58
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_session_token] = key }
59
+
60
+ option :region,
61
+ :long => "--region REGION",
62
+ :description => "Your AWS region",
63
+ :proc => Proc.new { |key| Chef::Config[:knife][:region] = key }
64
+
65
+ option :use_iam_profile,
66
+ :long => "--use-iam-profile",
67
+ :description => "Use IAM profile assigned to current machine",
68
+ :boolean => true,
69
+ :default => false,
70
+ :proc => Proc.new { |key| Chef::Config[:knife][:use_iam_profile] = key }
71
+
32
72
  def run
33
73
  $stdout.sync = true
34
74
 
35
75
  validate!
36
-
76
+
37
77
  stack_name = @name_args[0]
38
-
39
- if stack_name.nil?
40
- show_usage
41
- ui.error("You must specify a stack name")
42
- exit 1
43
- end
44
-
78
+
79
+ if stack_name.nil?
80
+ show_usage
81
+ ui.error("You must specify a stack name")
82
+ exit 1
83
+ end
84
+
45
85
  options = {}
46
86
  options['StackName'] = stack_name
47
87
  begin
48
88
  response = connection.describe_stacks(options)
49
- rescue Excon::Errors::BadRequest => e
50
- i= e.response.body.index("<Message>")
89
+ rescue Excon::Errors::BadRequest => e
90
+ i= e.response.body.index("<Message>")
51
91
  j = e.response.body.index("</Message>")
52
92
  if !i.nil? and !j.nil?
53
93
  ui.error(e.response.body[i+9,j-i-9])
@@ -55,15 +95,15 @@ class Chef
55
95
  print "\n#{e.response.body}"
56
96
  end
57
97
  exit 1
58
- end
59
-
60
- puts "\n"
61
- confirm("Do you really want to delete stack #{stack_name}")
62
-
98
+ end
99
+
100
+ puts "\n"
101
+ confirm("Do you really want to delete stack #{stack_name}")
102
+
63
103
  begin
64
104
  response = connection.delete_stack(stack_name)
65
105
  rescue Excon::Errors::BadRequest => e
66
- i= e.response.body.index("<Message>")
106
+ i= e.response.body.index("<Message>")
67
107
  j = e.response.body.index("</Message>")
68
108
  if !i.nil? and !j.nil?
69
109
  ui.error(e.response.body[i+9,j-i-9])
@@ -74,8 +114,8 @@ class Chef
74
114
  else
75
115
  message = "Stack #{stack_name} delete started"
76
116
  print "\n#{ui.color(message, :green)}"
77
- end
78
- end
79
- end
117
+ end
118
+ end
119
+ end
80
120
  end
81
121
  end