kontena-plugin-cloud 1.1.1 → 1.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ae8fbe7ad9b70e0f0bc5c56b841dbc57991b245
4
- data.tar.gz: a9663fc54506816ac95156e46c86ed401bab7e7b
3
+ metadata.gz: dc3a8c3040ed8e7a6b9cbd96270d24839b536afc
4
+ data.tar.gz: af258da9b87003457ff111d2e484f7f1d44ce645
5
5
  SHA512:
6
- metadata.gz: d34d7bafe586d8dc217210bb6f1209501da31ddc9ff7da86cd730b013a589670825bc65c02b62e919f7d1fc13cf9d43b4e3f0b883bb48eeb01eef5ac272c4a90
7
- data.tar.gz: 73db780fb7f58fef28c64060d04d809adbc8ce0e7eef29b8b03e64487dc465a8e83f42422319732882567dccf5878228b00140c17659ac39a8a2c24341bf40b9
6
+ metadata.gz: 9776738f6ee1d8b0299a1dd526d2156f8642487924327e6f1f2e55de5264a14a84dd9ec80791dc8731252ca9581b728ead499c0de3da016b70c57da190282245
7
+ data.tar.gz: b9a5a54c84f784a5e1b70bbae31d4587e9504169ff043a14974f00be329f6293eaadbc20ead6a05efcc8a07bb5ab66f32b46597c817ee2ebd3343293c5f1b304
@@ -0,0 +1,15 @@
1
+ require_relative 'cloud_api_model'
2
+
3
+ module Kontena::Cli::Models
4
+ class Node
5
+ include CloudApiModel
6
+
7
+ def platform_id
8
+ @api_data.dig('relationships', 'platform', 'data', 'id')
9
+ end
10
+
11
+ def organization_id
12
+ @api_data.dig('relationships', 'organization', 'data', 'id')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../../../cli/models/node'
2
+ require_relative '../../../cli/models/platform'
3
+
4
+ module Kontena::Plugin::Cloud::Node::Common
5
+
6
+ def self.included(base)
7
+ if base.respond_to?(:option)
8
+ base.option '--platform', 'PLATFORM', 'Specify Kontena Cloud platform to use' do |platform|
9
+ config.current_master = platform
10
+ config.current_grid = platform.split('/')[1]
11
+ end
12
+ end
13
+ end
14
+
15
+ def compute_client
16
+ @compute_client ||= Kontena::Client.new(compute_url, config.current_account.token, prefix: '/')
17
+ end
18
+
19
+ def config
20
+ Kontena::Cli::Config.instance
21
+ end
22
+
23
+ def compute_url
24
+ ENV['COMPUTE_URL'] || 'https://compute.kontena.io'
25
+ end
26
+
27
+ def get_platform(org, id)
28
+ unless cached_platforms_by_id[id]
29
+ data = cloud_client.get("/organizations/#{org}/platforms/#{id}")['data']
30
+ if data
31
+ platform = Kontena::Cli::Models::Platform.new(data)
32
+ cached_platforms_by_id[id] = platform
33
+ end
34
+ end
35
+
36
+ cached_platforms_by_id[id]
37
+ end
38
+
39
+ def cached_platforms_by_id
40
+ @cached_platforms_by_id ||= {}
41
+ end
42
+ end
@@ -0,0 +1,77 @@
1
+ require 'kontena/machine/random_name'
2
+ require_relative 'common'
3
+ require_relative '../organization/common'
4
+ require_relative '../platform/common'
5
+
6
+ class Kontena::Plugin::Cloud::Node::CreateCommand < Kontena::Command
7
+ include Kontena::Cli::Common
8
+ include Kontena::Machine::RandomName
9
+ include Kontena::Plugin::Cloud::Node::Common
10
+ include Kontena::Plugin::Cloud::Organization::Common
11
+ include Kontena::Plugin::Cloud::Platform::Common
12
+
13
+ requires_current_account_token
14
+
15
+ option "--count", "COUNT", "How many nodes to create" do |count|
16
+ Integer(count)
17
+ end
18
+ option "--type", "TYPE", "Node type", required: true
19
+ option "--region", "REGION", "Region (us-east-1, eu-west-1, defaults to current platform region)"
20
+
21
+ def execute
22
+ org, platform = parse_platform_name(current_master.name)
23
+ platform = require_platform("#{org}/#{platform}")
24
+ grid = client.get("grids/#{current_grid}")
25
+ self.count.times do
26
+ create_node(platform, grid['token'])
27
+ end
28
+ end
29
+
30
+ def create_node(platform, token)
31
+ name = "#{generate_name}-#{rand(1..999)}"
32
+ node_token = SecureRandom.hex(32)
33
+ target_region = self.region || platform.region
34
+ spinner "Provisioning a node #{pastel.cyan(name)} to platform #{pastel.cyan(platform.to_path)}, region #{pastel.cyan(target_region)}" do
35
+ client.post("grids/#{current_grid}/nodes", {
36
+ name: name,
37
+ token: node_token
38
+ })
39
+
40
+ data = {
41
+ type: 'nodes',
42
+ attributes: {
43
+ name: name,
44
+ type: self.type,
45
+ region: target_region,
46
+ tokens: {
47
+ grid: token,
48
+ node: node_token
49
+ }
50
+ },
51
+ relationships: {
52
+ platform: {
53
+ data: {
54
+ type: 'platforms',
55
+ id: platform.id
56
+ }
57
+ }
58
+ }
59
+ }
60
+ compute_client.post("/organizations/#{current_organization}/nodes", { data: data })
61
+ end
62
+ end
63
+
64
+ def default_count
65
+ prompt.ask("How many nodes?", default: 1).to_i
66
+ end
67
+
68
+ def default_type
69
+ node_types = compute_client.get("/node_types")['data']
70
+ prompt.select("Choose node type:") do |menu|
71
+ menu.default 3
72
+ node_types.each do |t|
73
+ menu.choice "#{t['id']} (#{t.dig('attributes', 'cpus')}xCPU, #{t.dig('attributes', 'memory')}GB, #{t.dig('attributes', 'disk')}GB SSD)", t['id']
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,49 @@
1
+ require_relative 'common'
2
+ require_relative '../organization/common'
3
+ require_relative '../platform/common'
4
+
5
+ class Kontena::Plugin::Cloud::Node::ListCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Cli::TableGenerator::Helper
8
+ include Kontena::Plugin::Cloud::Node::Common
9
+ include Kontena::Plugin::Cloud::Platform::Common
10
+ include Kontena::Plugin::Cloud::Organization::Common
11
+
12
+ requires_current_account_token
13
+
14
+ def execute
15
+ org, platform = parse_platform_name(current_master.name)
16
+ platform = require_platform("#{org}/#{platform}")
17
+ nodes = compute_client.get("/organizations/#{org}/nodes")['data']
18
+ nodes.delete_if { |n| n.dig('attributes', 'state') == 'terminated' }
19
+ print_table(nodes) do |n|
20
+ node = Kontena::Cli::Models::Node.new(n)
21
+ n['name'] = "#{state_icon(node.state)} #{node.name}"
22
+ n['type'] = node.type
23
+ n['region'] = node.region
24
+ end
25
+ end
26
+
27
+ def default_organization
28
+ prompt_organization
29
+ end
30
+
31
+ def fields
32
+ {
33
+ 'name' => 'name',
34
+ 'type' => 'type',
35
+ 'region' => 'region'
36
+ }
37
+ end
38
+
39
+ def state_icon(state)
40
+ case state
41
+ when nil
42
+ " ".freeze
43
+ when 'running'.freeze
44
+ pastel.green('⊛'.freeze)
45
+ else
46
+ pastel.dark('⊝'.freeze)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,67 @@
1
+ require_relative 'common'
2
+ require_relative '../organization/common'
3
+ require_relative '../platform/common'
4
+
5
+ class Kontena::Plugin::Cloud::Node::ShellCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Plugin::Cloud::Platform::Common
8
+ include Kontena::Plugin::Cloud::Node::Common
9
+
10
+ requires_current_account_token
11
+
12
+ parameter "NAME", "Node name"
13
+ parameter "[CMD] ...", "Command"
14
+
15
+ def execute
16
+ service_name = "#{name}-shell-#{rand(1..10_000)}"
17
+
18
+ service = nil
19
+ spinner "Creating shell session to node #{pastel.cyan(name)}" do
20
+ service = create_service(service_name, name)
21
+ end
22
+
23
+ exec_opts = ['-i']
24
+ exec_opts << 't' if STDIN.tty?
25
+ if cmd_list.empty?
26
+ exec_command = ''
27
+ else
28
+ exec_command = "-c \"#{cmd_list.join(' ')}\""
29
+ end
30
+
31
+ Kontena.run!([
32
+ 'service', 'exec', exec_opts.join(''), '--shell', service_name,
33
+ "nsenter --target 1 --mount --uts --net --pid -- su #{exec_command} - core"
34
+ ])
35
+ ensure
36
+ remove_service(service) if service
37
+ end
38
+
39
+ def create_service(service_name, node_name)
40
+ data = {
41
+ name: service_name,
42
+ image: 'kontena/nsenter:latest',
43
+ stateful: false,
44
+ cmd: ['sleep', '60000'],
45
+ pid: 'host',
46
+ privileged: true,
47
+ affinity: [
48
+ "node==#{node_name}"
49
+ ],
50
+ env: [
51
+ "TERM=xterm"
52
+ ]
53
+ }
54
+ service = client.post("grids/#{current_grid}/services", data)
55
+ deployment = client.post("services/#{service['id']}/deploy", {})
56
+ until deployment['finished_at'] do
57
+ sleep 1
58
+ deployment = client.get("services/#{service['id']}/deploys/#{deployment['id']}", {})
59
+ end
60
+
61
+ service
62
+ end
63
+
64
+ def remove_service(service)
65
+ client.delete("services/#{service['id']}", {})
66
+ end
67
+ end
@@ -0,0 +1,62 @@
1
+ require_relative 'common'
2
+ require_relative '../organization/common'
3
+ require_relative '../platform/common'
4
+
5
+ class Kontena::Plugin::Cloud::Node::TerminateCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Plugin::Cloud::Platform::Common
8
+ include Kontena::Plugin::Cloud::Node::Common
9
+
10
+ requires_current_account_token
11
+
12
+ parameter "[NAME]", "Node name"
13
+ option "--force", :flag, "Force remove", default: false, attribute_name: :forced
14
+
15
+ def execute
16
+ org, platform = parse_platform_name(current_master.name)
17
+ unless self.name
18
+ name = prompt_name(platform, org)
19
+ else
20
+ exit_with_error "Invalid name" if org.nil? || platform.nil?
21
+ name = self.name
22
+ end
23
+
24
+ confirm_command(name) unless forced?
25
+
26
+ nodes = compute_client.get("/organizations/#{org}/nodes")['data'].map { |n|
27
+ Kontena::Cli::Models::Node.new(n)
28
+ }
29
+ node = nodes.find { |n| n.name == name }
30
+ exit_with_error "Node not found" unless node
31
+
32
+ spinner "Terminating node #{pastel.cyan(node.name)} from platform #{pastel.cyan("#{org}/#{platform}")}" do
33
+ compute_client.delete("/organizations/#{org}/nodes/#{node.id}")
34
+ end
35
+ platform = get_platform(org, node.platform_id)
36
+ if platform
37
+ client.delete("nodes/#{current_grid}/#{name}")
38
+ end
39
+ end
40
+
41
+ def prompt_name(platform, org)
42
+ platform = find_platform_by_name(platform, org)
43
+ exit_with_error "Platform not selected" unless platform
44
+
45
+ nodes = compute_client.get("/organizations/#{org}/nodes")['data'].map { |n|
46
+ Kontena::Cli::Models::Node.new(n)
47
+ }
48
+ nodes.delete_if { |n| n.platform_id != platform.id || n.state == 'terminated' }
49
+ exit_with_error "No nodes" if nodes.size == 0
50
+ grid_nodes = client.get("grids/#{current_grid}/nodes")['nodes']
51
+ prompt.select("Choose node") do |menu|
52
+ nodes.each do |node|
53
+ grid_node = grid_nodes.find { |n| n['name'] == node.name }
54
+ if grid_node
55
+ menu.choice "#{node.name} #{grid_node['initial_member'] ? '(initial)' : ''}", node.name
56
+ else
57
+ menu.choice "#{node.name} (orphan)", node.name
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,10 @@
1
+ class Kontena::Plugin::Cloud::NodeCommand < Kontena::Command
2
+
3
+ subcommand ['list', 'ls'], 'List cloud nodes', load_subcommand('kontena/plugin/cloud/node/list_command')
4
+ subcommand ['shell'], 'Jump into node shell', load_subcommand('kontena/plugin/cloud/node/shell_command')
5
+ subcommand ['create'], 'Create cloud node', load_subcommand('kontena/plugin/cloud/node/create_command')
6
+ subcommand ['terminate'], 'Terminate cloud node', load_subcommand('kontena/plugin/cloud/node/terminate_command')
7
+
8
+ def execute
9
+ end
10
+ end
@@ -52,9 +52,7 @@ module Kontena::Plugin::Cloud::Platform::Common
52
52
  p = find_platform_by_name(platform, org)
53
53
  exit_with_error("Platform not found") unless p
54
54
  unless platform_config_exists?(p.to_path)
55
- spinner "Generating platform token" do
56
- login_to_platform("#{current_organization}/#{platform}", p.url)
57
- end
55
+ login_to_platform("#{current_organization}/#{platform}", p.url)
58
56
  end
59
57
  self.current_master = "#{current_organization}/#{platform}"
60
58
  self.current_grid = p.grid_id
@@ -0,0 +1,17 @@
1
+ class Kontena::Plugin::Cloud::Token::CreateCommand < Kontena::Command
2
+ include Kontena::Cli::Common
3
+
4
+ requires_current_account_token
5
+
6
+ parameter "[NAME]", "Description for the personal access token"
7
+
8
+ def execute
9
+ data = { attributes: { name: self.name }}
10
+ token = cloud_client.post("/user/personal_access_tokens", { data: data })['data']
11
+ puts token.dig('attributes','access-token')
12
+ end
13
+
14
+ def default_name
15
+ prompt.ask("Name:")
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ class Kontena::Plugin::Cloud::Token::ListCommand < Kontena::Command
2
+ include Kontena::Cli::Common
3
+ include Kontena::Cli::TableGenerator::Helper
4
+
5
+ requires_current_account_token
6
+
7
+ def execute
8
+ tokens = cloud_client.get('/user/personal_access_tokens')['data']
9
+ print_table(tokens) do |row|
10
+ row.merge!(row['attributes'])
11
+ end
12
+ end
13
+
14
+ def fields
15
+ {
16
+ id: 'id',
17
+ created: 'created-at',
18
+ name: 'name'
19
+ }
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ class Kontena::Plugin::Cloud::Token::RemoveCommand < Kontena::Command
2
+ include Kontena::Cli::Common
3
+ include Kontena::Cli::TableGenerator::Helper
4
+
5
+ requires_current_account_token
6
+ parameter "[ID]", "ID of the token"
7
+ option "--force", :flag, "Force remove", default: false, attribute_name: :forced
8
+
9
+ def execute
10
+ id = self.id
11
+ confirm unless forced?
12
+ cloud_client.delete("/user/personal_access_tokens/#{id}")
13
+ end
14
+
15
+
16
+ def prompt_token
17
+ tokens = cloud_client.get('/user/personal_access_tokens')['data']
18
+ prompt.select("Choose token:") do |menu|
19
+ tokens.each do |d|
20
+ menu.choice d.dig('attributes', 'name'), d['id']
21
+ end
22
+ end
23
+ end
24
+
25
+ def default_id
26
+ prompt_token
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ class Kontena::Plugin::Cloud::TokenCommand < Kontena::Command
2
+
3
+ subcommand ['list', 'ls'], 'List personal access tokens', load_subcommand('kontena/plugin/cloud/token/list_command')
4
+ subcommand 'create', 'Create personal access token', load_subcommand('kontena/plugin/cloud/token/create_command')
5
+ subcommand ['remove', 'rm'], 'Remove personal access token', load_subcommand('kontena/plugin/cloud/token/remove_command')
6
+ def execute
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  module Kontena
2
2
  module Plugin
3
3
  module Cloud
4
- VERSION = "1.1.1"
4
+ VERSION = "1.2.0.pre1"
5
5
 
6
6
  module Organization
7
7
  module User; end
@@ -9,9 +9,13 @@ module Kontena
9
9
 
10
10
  module Region; end
11
11
 
12
+ module Node; end
13
+
12
14
  module Platform
13
15
  module User; end
14
16
  end
17
+
18
+ module Token; end;
15
19
  end
16
20
 
17
21
  module Grid
@@ -1,8 +1,10 @@
1
1
  class Kontena::Cli::CloudCommand < Kontena::Command
2
2
 
3
3
  subcommand 'platform', 'Kontena platform specific commands', load_subcommand('kontena/plugin/cloud/platform_command')
4
+ subcommand 'node', 'Kontena node specific commands', load_subcommand('kontena/plugin/cloud/node_command')
4
5
  subcommand ['organization', 'org'], 'Organization specific commands', load_subcommand('kontena/plugin/cloud/organization_command')
5
6
  subcommand 'region', 'Region specific commands', load_subcommand('kontena/plugin/cloud/region_command')
7
+ subcommand 'token', 'Personal access token specific commands', load_subcommand('kontena/plugin/cloud/token_command')
6
8
 
7
9
  def execute
8
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kontena-plugin-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kontena, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-17 00:00:00.000000000 Z
11
+ date: 2017-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kontena-cli
@@ -71,9 +71,16 @@ files:
71
71
  - lib/kontena/cli/models/cloud_api_model.rb
72
72
  - lib/kontena/cli/models/grid.rb
73
73
  - lib/kontena/cli/models/master_api_model.rb
74
+ - lib/kontena/cli/models/node.rb
74
75
  - lib/kontena/cli/models/organization.rb
75
76
  - lib/kontena/cli/models/platform.rb
76
77
  - lib/kontena/plugin/cloud.rb
78
+ - lib/kontena/plugin/cloud/node/common.rb
79
+ - lib/kontena/plugin/cloud/node/create_command.rb
80
+ - lib/kontena/plugin/cloud/node/list_command.rb
81
+ - lib/kontena/plugin/cloud/node/shell_command.rb
82
+ - lib/kontena/plugin/cloud/node/terminate_command.rb
83
+ - lib/kontena/plugin/cloud/node_command.rb
77
84
  - lib/kontena/plugin/cloud/organization/common.rb
78
85
  - lib/kontena/plugin/cloud/organization/list_command.rb
79
86
  - lib/kontena/plugin/cloud/organization/remove_command.rb
@@ -100,6 +107,10 @@ files:
100
107
  - lib/kontena/plugin/cloud/platform_command.rb
101
108
  - lib/kontena/plugin/cloud/region/list_command.rb
102
109
  - lib/kontena/plugin/cloud/region_command.rb
110
+ - lib/kontena/plugin/cloud/token/create_command.rb
111
+ - lib/kontena/plugin/cloud/token/list_command.rb
112
+ - lib/kontena/plugin/cloud/token/remove_command.rb
113
+ - lib/kontena/plugin/cloud/token_command.rb
103
114
  - lib/kontena/plugin/cloud_command.rb
104
115
  - lib/kontena_cli_plugin.rb
105
116
  homepage: https://kontena.io
@@ -117,9 +128,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
128
  version: '0'
118
129
  required_rubygems_version: !ruby/object:Gem::Requirement
119
130
  requirements:
120
- - - ">="
131
+ - - ">"
121
132
  - !ruby/object:Gem::Version
122
- version: '0'
133
+ version: 1.3.1
123
134
  requirements: []
124
135
  rubyforge_project:
125
136
  rubygems_version: 2.6.14