kontena-plugin-cloud 1.1.1 → 1.2.0.pre1

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: 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