kontena-plugin-aws 0.2.0.pre1 → 0.2.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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MjkzMTFkZDliMjJjNTI1NzhjYWFmMGZkYzllMzFmZDM2NjQxMzgwMQ==
4
+ OWYyM2NkMmM4YTdkZGU5ZDAzZWRiMzUyMjYwZDFjMDA0ZmI0ZTRkOA==
5
5
  data.tar.gz: !binary |-
6
- ODIyMjJlNDM3NTRhOWNiM2UwZTJkZDRmZmEyY2U2ZDM0NjM1YTcxNQ==
6
+ MWM3MmY3NTgzMzQzZWFkZjQyODA2OTg5Yzk0ZmFkOTZiNTI3OTA0Nw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmUwNDkwZTdjNjRkMWQyNGYzYjM0M2ZmYjc0ODI3MDczYzA5YWQxZWFiODcx
10
- ZDBhMzI0OTEyMWY4N2M1MmRlYzI2ZjRmNjE5ZGExZjEwY2E1OWE1NWYxMzk4
11
- NTYxYjY1OTUxNWU4ZTg1MTgyMjUyNTJiZDgwODM0MjQ4ZDljY2Y=
9
+ YTBhODExYWY2NzZkZjc0YTgxNTJhNjM5MDFhOGI0NTY0YTMyOTkxMzhmMmJm
10
+ Y2E1N2Y4NDJkNjc5MGMwZDQzMzY1YWFhMTUzY2VjZDM1ZDM2YTM3N2U0NDAw
11
+ MGU3MjNiMDBhYzI3YjZmYWMzZGQ5YjA4ODVlNWY1ZTc2OWY5ZjA=
12
12
  data.tar.gz: !binary |-
13
- NjM4MGQ2YjMzZjUxMGE2ZTY3ODQ4ZTAzYmYzNDE5YmQ1Njc3OGQ3Nzg4YTcx
14
- MTk3NzA1OWI0OWE4MjI4NjQyZWQ5ZTMxODIwM2M2MjYwYzJkOWE4Nzc5NDNl
15
- ZjBlZDllOWVmNmY3MDY5MjI5YjM0MGMwZTVmM2MxOWJlNWM0NzY=
13
+ MWUyZDlhY2Y5NzQ5MjQ0NTU0Njc4NTJmMjYxMmE0ZTJlZThkZjhmNzlkZGEw
14
+ NDE0MDliYWRmYjJkMmRkZmRlOGM3ZDU4YjlkYTNhODhhM2QzOTAyODg2YjFl
15
+ NGQ5MTczMDY0MjJhY2ZiZTJlNzAyMGZkNDY3YjI0MjczYzkwZjY=
@@ -33,7 +33,16 @@ coreos:
33
33
  DOMAINS=kontena.local
34
34
  [DHCP]
35
35
  UseDNS=false
36
-
36
+ - name: etcd2.service
37
+ command: start
38
+ enable: true
39
+ content: |
40
+ Description=etcd 2.0
41
+ After=docker.service
42
+ [Service]
43
+ Restart=always
44
+ RestartSec=5
45
+ ExecStart=/usr/bin/docker logs --tail=10 -f kontena-etcd
37
46
  - name: 10-weave.network
38
47
  runtime: false
39
48
  content: |
@@ -89,11 +89,11 @@ coreos:
89
89
  --link kontena-server-mongo:mongodb \
90
90
  -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
91
91
  <% end -%>
92
- <% if server_name %>
93
- -e KONTENA_SERVER_NAME=<%= server_name %> \
92
+ <% if server_name -%>
93
+ -e SERVER_NAME=<%= server_name %> \
94
94
  <% end -%>
95
- <% if initial_admin_code %>
96
- -e KONTENA_INITIAL_ADMIN_CODE=<%= intial_admin_code %> \
95
+ <% if initial_admin_code -%>
96
+ -e INITIAL_ADMIN_CODE=<%= initial_admin_code %> \
97
97
  <% end -%>
98
98
  -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
99
99
  kontena/server:${KONTENA_VERSION}
@@ -2,6 +2,7 @@ require 'fileutils'
2
2
  require 'erb'
3
3
  require 'open3'
4
4
  require 'securerandom'
5
+ require 'json'
5
6
 
6
7
  require_relative 'common'
7
8
 
@@ -10,7 +11,7 @@ module Kontena::Machine::Aws
10
11
  include Kontena::Machine::RandomName
11
12
  include Kontena::Machine::CertHelper
12
13
  include Common
13
- include Kontena::Cli::ShellSpinner
14
+ include Kontena::Cli::Common
14
15
 
15
16
  attr_reader :ec2, :http_client, :region
16
17
 
@@ -30,7 +31,7 @@ module Kontena::Machine::Aws
30
31
  abort('Invalid ssl cert') unless File.exists?(File.expand_path(opts[:ssl_cert]))
31
32
  ssl_cert = File.read(File.expand_path(opts[:ssl_cert]))
32
33
  else
33
- spinner "Generating self-signed SSL certificate" do
34
+ spinner "Generating a self-signed SSL certificate" do
34
35
  ssl_cert = generate_self_signed_cert
35
36
  end
36
37
  end
@@ -89,10 +90,11 @@ module Kontena::Machine::Aws
89
90
  ]
90
91
  })
91
92
 
92
- spinner "Creating AWS instance #{name.colorize(:cyan)} " do
93
+ spinner "Creating an AWS instance #{name.colorize(:cyan)} " do
93
94
  sleep 1 until ec2_instance.reload.state.name == 'running'
94
95
  end
95
96
  public_ip = ec2_instance.reload.public_ip_address
97
+ master_version = nil
96
98
  if public_ip.nil?
97
99
  master_url = "https://#{ec2_instance.private_ip_address}"
98
100
  puts "Could not get public IP for the created master, private connect url is: #{master_url}"
@@ -101,16 +103,21 @@ module Kontena::Machine::Aws
101
103
  Excon.defaults[:ssl_verify_peer] = false
102
104
  http_client = Excon.new(master_url, :connect_timeout => 10)
103
105
  spinner "Waiting for #{name.colorize(:cyan)} to start " do
104
- sleep 1 until master_running?(http_client)
106
+ sleep 0.5 until master_running?(http_client)
105
107
  end
108
+
109
+ spinner "Retrieving Kontena Master version" do
110
+ master_version = JSON.parse(http_client.get(path: '/').body)["version"] rescue nil
111
+ end
112
+
113
+ spinner "Kontena Master #{master_version} is now running at #{master_url}"
106
114
  end
107
- puts
108
- puts "Kontena Master is now running at #{master_url}".colorize(:green)
109
- puts
110
115
  {
111
116
  name: name.sub('kontena-master-', ''),
112
117
  public_ip: public_ip,
113
- code: opts[:initial_admin_code]
118
+ code: opts[:initial_admin_code],
119
+ provider: 'aws',
120
+ version: master_version
114
121
  }
115
122
  end
116
123
 
@@ -33,69 +33,82 @@ module Kontena::Machine::Aws
33
33
  resolve_security_groups_to_ids(opts[:security_groups], opts[:vpc]) :
34
34
  ensure_security_group(opts[:grid], opts[:vpc])
35
35
 
36
- name = opts[:name ] || generate_name
37
-
38
36
  if opts[:subnet].nil?
39
37
  subnet = default_subnet(opts[:vpc], region+opts[:zone])
40
38
  else
41
39
  subnet = ec2.subnet(opts[:subnet])
42
40
  end
43
41
  dns_server = aws_dns_supported?(opts[:vpc]) ? '169.254.169.253' : '8.8.8.8'
44
- userdata_vars = {
45
- name: name,
46
- version: opts[:version],
47
- master_uri: opts[:master_uri],
48
- grid_token: opts[:grid_token],
49
- dns_server: dns_server
50
- }
51
-
52
- ec2_instance = ec2.create_instances({
53
- image_id: ami,
54
- min_count: 1,
55
- max_count: 1,
56
- instance_type: opts[:type],
57
- key_name: opts[:key_pair],
58
- user_data: Base64.encode64(user_data(userdata_vars)),
59
- block_device_mappings: [
60
- {
61
- device_name: '/dev/xvda',
62
- virtual_name: 'Root',
63
- ebs: {
64
- volume_size: opts[:storage],
65
- volume_type: 'gp2'
66
- }
67
- }
68
- ],
69
- network_interfaces: [
70
- {
71
- device_index: 0,
72
- subnet_id: subnet.subnet_id,
73
- groups: security_groups,
74
- associate_public_ip_address: opts[:associate_public_ip],
75
- delete_on_termination: true
76
- }
77
- ]
78
- }).first
79
- ec2_instance.create_tags({
80
- tags: [
81
- {key: 'Name', value: name},
82
- {key: 'kontena_grid', value: opts[:grid]}
83
- ]
84
- })
42
+ instances = []
43
+ opts[:count].to_i.times do |i|
44
+ if opts[:name] && opts[:count].to_i > 1
45
+ name = "#{opts[:name]}-#{i+1}"
46
+ elsif opts[:name]
47
+ name = opts[:name]
48
+ else
49
+ name = generate_name
50
+ end
85
51
 
86
- spinner "Creating AWS instance #{name.colorize(:cyan)} " do
87
- sleep 1 until ec2_instance.reload.state.name == 'running'
52
+ userdata_vars = {
53
+ name: name,
54
+ version: opts[:version],
55
+ master_uri: opts[:master_uri],
56
+ grid_token: opts[:grid_token],
57
+ dns_server: dns_server
58
+ }
59
+
60
+ ec2_instance = ec2.create_instances({
61
+ image_id: ami,
62
+ min_count: 1,
63
+ max_count: 1,
64
+ instance_type: opts[:type],
65
+ key_name: opts[:key_pair],
66
+ user_data: Base64.encode64(user_data(userdata_vars)),
67
+ block_device_mappings: [
68
+ {
69
+ device_name: '/dev/xvda',
70
+ virtual_name: 'Root',
71
+ ebs: {
72
+ volume_size: opts[:storage],
73
+ volume_type: 'gp2'
74
+ }
75
+ }
76
+ ],
77
+ network_interfaces: [
78
+ {
79
+ device_index: 0,
80
+ subnet_id: subnet.subnet_id,
81
+ groups: security_groups,
82
+ associate_public_ip_address: opts[:associate_public_ip],
83
+ delete_on_termination: true
84
+ }
85
+ ]
86
+ }).first
87
+ ec2_instance.create_tags({
88
+ tags: [
89
+ {key: 'Name', value: name},
90
+ {key: 'kontena_grid', value: opts[:grid]}
91
+ ]
92
+ })
93
+
94
+ spinner "Creating AWS instance #{name.colorize(:cyan)} " do
95
+ sleep 1 until ec2_instance.reload.state.name == 'running'
96
+ end
97
+ instances << name
88
98
  end
89
- node = nil
90
- spinner "Waiting for node #{name.colorize(:cyan)} join to grid #{opts[:grid].colorize(:cyan)} " do
91
- sleep 1 until node = instance_exists_in_grid?(opts[:grid], name)
99
+ instances.each do |instance_name|
100
+ node = nil
101
+ spinner "Waiting for node #{instance_name.colorize(:cyan)} join to grid #{opts[:grid].colorize(:cyan)} " do
102
+ sleep 1 until node = instance_exists_in_grid?(opts[:grid], instance_name)
103
+ end
104
+ labels = [
105
+ "region=#{region}",
106
+ "az=#{opts[:zone]}",
107
+ "provider=aws",
108
+ "type=#{opts[:type]}"
109
+ ]
110
+ set_labels(node, labels)
92
111
  end
93
- labels = [
94
- "region=#{region}",
95
- "az=#{opts[:zone]}",
96
- "provider=aws"
97
- ]
98
- set_labels(node, labels)
99
112
  end
100
113
 
101
114
  ##
@@ -1,7 +1,7 @@
1
1
  module Kontena
2
2
  module Plugin
3
3
  module Aws
4
- VERSION = "0.2.0.pre1"
4
+ VERSION = "0.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -1,20 +1,22 @@
1
1
  require 'securerandom'
2
+ require_relative '../prompts'
2
3
 
3
4
  module Kontena::Plugin::Aws::Master
4
5
  class CreateCommand < Kontena::Command
5
6
  include Kontena::Cli::Common
7
+ include Kontena::Plugin::Aws::Prompts
6
8
 
7
9
  option "--name", "[NAME]", "Set Master name"
8
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
9
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
10
- option "--key-pair", "KEY_PAIR", "EC2 key pair name", required: true
10
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
11
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
12
+ option "--key-pair", "KEY_PAIR", "EC2 key pair name"
11
13
  option "--ssl-cert", "SSL CERT", "SSL certificate file (default: generate self-signed cert)"
12
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
13
- option "--zone", "ZONE", "EC2 Availability Zone", default: 'a'
14
- option "--vpc-id", "VPC ID", "Virtual Private Cloud (VPC) ID (default: default vpc)"
15
- option "--subnet-id", "SUBNET ID", "VPC option to specify subnet to launch instance into (default: first subnet from vpc/az)"
16
- option "--type", "SIZE", "Instance type", default: 't2.small'
17
- option "--storage", "STORAGE", "Storage size (GiB)", default: '30'
14
+ option "--region", "REGION", "EC2 Region", environment_variable: "AWS_REGION"
15
+ option "--zone", "ZONE", "EC2 Availability Zone (a,b,c,d,e)"
16
+ option "--vpc-id", "VPC ID", "Virtual Private Cloud (VPC) ID"
17
+ option "--subnet-id", "SUBNET ID", "VPC option to specify subnet to launch instance into (default: first subnet in vpc/az)"
18
+ option "--type", "SIZE", "Instance type"
19
+ option "--storage", "STORAGE", "Storage size (GiB)"
18
20
  option "--vault-secret", "VAULT_SECRET", "Secret key for Vault (default: generate random secret)"
19
21
  option "--vault-iv", "VAULT_IV", "Initialization vector for Vault (default: generate random iv)"
20
22
  option "--mongodb-uri", "URI", "External MongoDB uri (optional)"
@@ -24,18 +26,28 @@ module Kontena::Plugin::Aws::Master
24
26
 
25
27
  def execute
26
28
  require 'kontena/machine/aws'
29
+ aws_access_key = ask_aws_access_key
30
+ aws_secret_key = ask_aws_secret_key
31
+ aws_region = ask_aws_region(aws_access_key, aws_secret_key)
32
+ aws_zone = ask_aws_az(aws_access_key, aws_secret_key, aws_region)
33
+ aws_vpc_id = ask_aws_vpc(aws_access_key, aws_secret_key, aws_region)
27
34
 
28
- provisioner = provisioner(access_key, secret_key, region)
35
+ exit_with_error("Could not find any Virtual Private Cloud (VPC). Please create one in the AWS console first.") unless aws_vpc_id
36
+ aws_subnet_id = ask_aws_subnet(aws_access_key, aws_secret_key, aws_region, aws_zone, aws_vpc_id)
37
+ aws_key_pair = ask_aws_key_pair(aws_access_key, aws_secret_key, aws_region)
38
+ aws_type = ask_aws_instance_type
39
+ aws_storage = ask_aws_storage
40
+ provisioner = provisioner(aws_access_key, aws_secret_key, aws_region)
29
41
  provisioner.run!(
30
42
  name: name,
31
- type: type,
32
- vpc: vpc_id,
33
- zone: zone,
34
- subnet: subnet_id,
43
+ type: aws_type,
44
+ vpc: aws_vpc_id,
45
+ zone: aws_zone,
46
+ subnet: aws_subnet_id,
35
47
  ssl_cert: ssl_cert,
36
- storage: storage,
48
+ storage: aws_storage,
37
49
  version: version,
38
- key_pair: key_pair,
50
+ key_pair: aws_key_pair,
39
51
  vault_secret: vault_secret || SecureRandom.hex(24),
40
52
  vault_iv: vault_iv || SecureRandom.hex(24),
41
53
  mongodb_uri: mongodb_uri,
@@ -2,17 +2,19 @@ module Kontena::Plugin::Aws::Nodes
2
2
  class CreateCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
+ include Kontena::Plugin::Aws::Prompts
5
6
 
6
7
  parameter "[NAME]", "Node name"
7
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
8
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
9
- option "--key-pair", "KEY_PAIR", "EC2 Key Pair", required: true
10
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
11
- option "--zone", "ZONE", "EC2 Availability Zone", default: 'a'
8
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
9
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
10
+ option "--key-pair", "KEY_PAIR", "EC2 Key Pair"
11
+ option "--region", "REGION", "EC2 Region", environment_variable: "AWS_REGION"
12
+ option "--zone", "ZONE", "EC2 Availability Zone (a,b,c,d,e)"
12
13
  option "--vpc-id", "VPC ID", "Virtual Private Cloud (VPC) ID (default: default vpc)"
13
14
  option "--subnet-id", "SUBNET ID", "VPC option to specify subnet to launch instance into (default: first subnet in vpc/az)"
14
- option "--type", "SIZE", "Instance type", default: 't2.small'
15
- option "--storage", "STORAGE", "Storage size (GiB)", default: '30'
15
+ option "--type", "SIZE", "Instance type"
16
+ option "--storage", "STORAGE", "Storage size (GiB)"
17
+ option "--count", "COUNT", "How many instances to create"
16
18
  option "--version", "VERSION", "Define installed Kontena version", default: 'latest'
17
19
  option "--associate-public-ip-address", :flag, "Whether to associated public IP in case the VPC defaults to not doing it", default: true, attribute_name: :associate_public_ip
18
20
  option "--security-groups", "SECURITY GROUPS", "Comma separated list of security groups (names) where the new instance will be attached (default: create grid specific group if not already existing)"
@@ -23,19 +25,31 @@ module Kontena::Plugin::Aws::Nodes
23
25
 
24
26
  require 'kontena/machine/aws'
25
27
  grid = fetch_grid(current_grid)
26
- provisioner = provisioner(client(require_token), access_key, secret_key, region)
28
+ aws_access_key = ask_aws_access_key
29
+ aws_secret_key = ask_aws_secret_key
30
+ aws_region = ask_aws_region(aws_access_key, aws_secret_key)
31
+ aws_zone = ask_aws_az(aws_access_key, aws_secret_key, aws_region)
32
+ aws_vpc_id = ask_aws_vpc(aws_access_key, aws_secret_key, aws_region)
33
+ exit_with_error("Could not find any Virtual Private Cloud (VPC). Please create one in the AWS console first.") unless aws_vpc_id
34
+ aws_subnet_id = ask_aws_subnet(aws_access_key, aws_secret_key, aws_region, aws_zone, aws_vpc_id)
35
+ aws_key_pair = ask_aws_key_pair(aws_access_key, aws_secret_key, aws_region)
36
+ aws_type = ask_aws_instance_type
37
+ aws_storage = ask_aws_storage
38
+ aws_count = ask_instance_count
39
+ provisioner = provisioner(client(require_token), aws_access_key, aws_secret_key, aws_region)
27
40
  provisioner.run!(
28
41
  master_uri: api_url,
29
42
  grid_token: grid['token'],
30
43
  grid: current_grid,
31
44
  name: name,
32
- type: type,
33
- vpc: vpc_id,
34
- zone: zone,
35
- subnet: subnet_id,
36
- storage: storage,
45
+ type: aws_type,
46
+ vpc: aws_vpc_id,
47
+ zone: aws_zone,
48
+ subnet: aws_subnet_id,
49
+ storage: aws_storage,
37
50
  version: version,
38
- key_pair: key_pair,
51
+ key_pair: aws_key_pair,
52
+ count: aws_count,
39
53
  associate_public_ip: associate_public_ip?,
40
54
  security_groups: security_groups
41
55
  )
@@ -55,5 +69,13 @@ module Kontena::Plugin::Aws::Nodes
55
69
  def provisioner(client, access_key, secret_key, region)
56
70
  Kontena::Machine::Aws::NodeProvisioner.new(client, access_key, secret_key, region)
57
71
  end
72
+
73
+ def ask_instance_count
74
+ if self.count.nil?
75
+ prompt.ask('How many instances?: ', default: 1)
76
+ else
77
+ self.count
78
+ end
79
+ end
58
80
  end
59
81
  end
@@ -1,25 +1,40 @@
1
1
  module Kontena::Plugin::Aws::Nodes
2
- class RestartCommand < Clamp::Command
2
+ class RestartCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
+ include Kontena::Plugin::Aws::Prompts
5
6
 
6
- parameter "NAME", "Node name"
7
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
8
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
9
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
7
+ parameter "[NAME]", "Node name"
8
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
9
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
10
+ option "--region", "REGION", "EC2 Region", environment_variable: "AWS_REGION"
10
11
 
11
12
  def execute
12
13
  require_api_url
13
14
  require_current_grid
15
+ token = require_token
16
+ node_name = self.name || ask_node(token)
17
+ node = client(token).get("grids/#{current_grid}/nodes/#{node_name}")
14
18
 
19
+ aws_access_key = ask_aws_access_key
20
+ aws_secret_key = ask_aws_secret_key
21
+ aws_region = self.region || resolve_or_ask_region(node, aws_access_key, aws_secret_key)
15
22
  require_relative '../../../machine/aws'
16
23
 
17
- restarter = restarter(access_key, secret_key, region)
18
- restarter.run!(name)
24
+ restarter = restarter(aws_access_key, aws_secret_key, aws_region)
25
+ restarter.run!(node_name)
19
26
  end
20
27
 
21
28
  def restarter(access_key, secret_key, region)
22
29
  Kontena::Machine::Aws::NodeRestarter.new(access_key, secret_key, region)
23
30
  end
31
+
32
+ def resolve_or_ask_region(node, access_key, secret_key)
33
+ if node['labels'] && region_label = node['labels'].find{ |l| l.split('=').first == 'region' }
34
+ region = region_label.split('=').last
35
+ end
36
+ region = ask_aws_region(access_key, secret_key) unless region
37
+ region
38
+ end
24
39
  end
25
40
  end
@@ -1,25 +1,43 @@
1
1
  module Kontena::Plugin::Aws::Nodes
2
- class TerminateCommand < Clamp::Command
2
+ class TerminateCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
+ include Kontena::Plugin::Aws::Prompts
5
6
 
6
- parameter "NAME", "Node name"
7
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
8
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
9
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
7
+ parameter "[NAME]", "Node name"
8
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
9
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
10
+ option "--region", "REGION", "EC2 Region (default: node's region)", environment_variable: "AWS_REGION"
11
+ option "--force", :flag, "Force remove", default: false, attribute_name: :forced
10
12
 
11
13
  def execute
12
14
  require_api_url
13
15
  require_current_grid
14
16
 
17
+ token = require_token
18
+ node_name = self.name || ask_node(token)
19
+ node = client(token).get("grids/#{current_grid}/nodes/#{node_name}")
20
+ aws_access_key = ask_aws_access_key
21
+ aws_secret_key = ask_aws_secret_key
22
+ aws_region = self.region || resolve_or_ask_region(node, aws_access_key, aws_secret_key)
23
+
24
+ confirm_command(node_name) unless forced?
15
25
  require 'kontena/machine/aws'
16
26
  grid = client(require_token).get("grids/#{current_grid}")
17
- destroyer = destroyer(client(require_token), access_key, secret_key, region)
18
- destroyer.run!(grid, name)
27
+ destroyer = destroyer(client(require_token), aws_access_key, aws_secret_key, aws_region)
28
+ destroyer.run!(grid, node_name)
19
29
  end
20
30
 
21
31
  def destroyer(client, access_key, secret_key, region)
22
32
  Kontena::Machine::Aws::NodeDestroyer.new(client, access_key, secret_key, region)
23
33
  end
34
+
35
+ def resolve_or_ask_region(node, access_key, secret_key)
36
+ if node['labels'] && region_label = node['labels'].find{ |l| l.split('=').first == 'region' }
37
+ region = region_label.split('=').last
38
+ end
39
+ region = ask_aws_region(access_key, secret_key) unless region
40
+ region
41
+ end
24
42
  end
25
43
  end
@@ -0,0 +1,148 @@
1
+ require 'aws-sdk'
2
+ module Kontena::Plugin::Aws::Prompts
3
+
4
+ def ask_aws_access_key
5
+ if self.access_key.nil?
6
+ prompt.ask('AWS access key: ', echo: false)
7
+ else
8
+ self.access_key
9
+ end
10
+ end
11
+
12
+ def ask_aws_secret_key
13
+ if self.secret_key.nil?
14
+ prompt.ask('AWS secret key: ', echo: false)
15
+ else
16
+ self.secret_key
17
+ end
18
+ end
19
+
20
+ def ask_aws_key_pair(access_key, secret_key, region)
21
+ if self.key_pair.nil?
22
+ prompt.select("Choose EC2 key pair: ") do |menu|
23
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
24
+ aws_client.describe_key_pairs.key_pairs.each{ |key_pair|
25
+ menu.choice key_pair.key_name, key_pair.key_name
26
+ }
27
+ end
28
+ else
29
+ self.key_pair
30
+ end
31
+ end
32
+
33
+ def ask_aws_region(access_key, secret_key, default = 'eu-west-1')
34
+ if self.region.nil?
35
+ prompt.select("Choose EC2 region: ") do |menu|
36
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: 'eu-west-1')
37
+ i = 1
38
+ aws_client.describe_regions.regions.sort_by{|r| r.region_name }.each{ |region|
39
+ menu.choice region.region_name, region.region_name
40
+ if region.region_name == default
41
+ menu.default i
42
+ end
43
+ i += 1
44
+ }
45
+ end
46
+ else
47
+ self.region
48
+ end
49
+ end
50
+
51
+ def ask_aws_az(access_key, secret_key, region)
52
+ if self.zone.nil?
53
+ prompt.select("Choose EC2 Availability Zone: ") do |menu|
54
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
55
+ aws_client.describe_availability_zones.availability_zones.sort_by{|r| r.zone_name }.each{ |zone|
56
+ if zone.state == 'available'
57
+ menu.choice zone.zone_name, zone.zone_name.sub(zone.region_name, '')
58
+ end
59
+ }
60
+ end
61
+ else
62
+ self.zone
63
+ end
64
+ end
65
+
66
+ def ask_aws_vpc(access_key, secret_key, region)
67
+ if self.vpc_id.nil?
68
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
69
+ vpcs = aws_client.describe_vpcs.vpcs
70
+ return nil if vpcs.size == 0
71
+ if vpcs.size == 1 && vpcs.first.state == "available"
72
+ vpcs.first.vpc_id
73
+ else
74
+ prompt.select("Choose Virtual Private Cloud (VPC) ID: ") do |menu|
75
+ vpcs.each{ |vpc|
76
+ if vpc.state == 'available'
77
+ name = vpc.vpc_id
78
+ name += ' (default)' if vpc.is_default
79
+ menu.choice name, vpc.vpc_id
80
+ end
81
+ }
82
+ end
83
+ end
84
+ else
85
+ self.vpc_id
86
+ end
87
+ end
88
+
89
+ def ask_aws_subnet(access_key, secret_key, region, zone, vpc)
90
+ if self.subnet_id.nil?
91
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
92
+ subnets_result = aws_client.describe_subnets(filters: [
93
+ { name: "vpc-id", values: [vpc] },
94
+ { name: "availability-zone", values: [zone]}
95
+ ])
96
+ subnets = subnets_result.subnets.sort_by{|s| s.cidr_block}
97
+ return nil if subnets.size == 0
98
+ if subnets.size == 1 && subnets.first.state == "available"
99
+ puts "Using Subnet (#{subnets.first.subnet_id})"
100
+ subnets.first.subnet_id
101
+ else
102
+ prompt.select("Specify subnet to launch instance into: ") do |menu|
103
+ subnets.each{ |subnet|
104
+ if subnet.state == 'available'
105
+ menu.choice "#{subnet.subnet_id} (#{subnet.cidr_block})", subnet.subnet_id
106
+ end
107
+ }
108
+ end
109
+ end
110
+ else
111
+ self.subnet_id
112
+ end
113
+ end
114
+
115
+ def ask_aws_instance_type(default = 't2.small')
116
+ if self.type.nil?
117
+ prompt.ask('Instance type: ', default: default)
118
+ else
119
+ self.type
120
+ end
121
+ end
122
+
123
+ def ask_aws_storage(default = '30')
124
+ if self.storage.nil?
125
+ prompt.ask('Storage size (GiB): ', default: default)
126
+ else
127
+ self.storage
128
+ end
129
+ end
130
+
131
+ def ask_node(token)
132
+ if self.name.nil?
133
+ nodes = client(token).get("grids/#{current_grid}/nodes")
134
+ nodes = nodes['nodes'].select{ |n|
135
+ n['labels'] && n['labels'].include?('provider=aws'.freeze)
136
+ }
137
+ raise "Did not find any nodes with label provider=aws" if nodes.size == 0
138
+ prompt.select("Select node: ") do |menu|
139
+ nodes.sort_by{|n| n['node_number'] }.reverse.each do |node|
140
+ initial = node['initial_member'] ? '(initial) ' : ''
141
+ menu.choice "#{node['name']} #{initial}", node['name']
142
+ end
143
+ end
144
+ else
145
+ self.name
146
+ end
147
+ end
148
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kontena-plugin-aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.pre1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kontena, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-30 00:00:00.000000000 Z
11
+ date: 2016-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kontena-cli
@@ -102,6 +102,7 @@ files:
102
102
  - lib/kontena/plugin/aws/nodes/create_command.rb
103
103
  - lib/kontena/plugin/aws/nodes/restart_command.rb
104
104
  - lib/kontena/plugin/aws/nodes/terminate_command.rb
105
+ - lib/kontena/plugin/aws/prompts.rb
105
106
  - lib/kontena/plugin/aws_command.rb
106
107
  - lib/kontena_cli_plugin.rb
107
108
  homepage: https://github.com/kontena/kontena-plugin-aws
@@ -119,9 +120,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
120
  version: '0'
120
121
  required_rubygems_version: !ruby/object:Gem::Requirement
121
122
  requirements:
122
- - - ! '>'
123
+ - - ! '>='
123
124
  - !ruby/object:Gem::Version
124
- version: 1.3.1
125
+ version: '0'
125
126
  requirements: []
126
127
  rubyforge_project:
127
128
  rubygems_version: 2.4.5