kontena-cli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ require 'kontena/client'
2
+ require_relative '../common'
3
+ require 'pp'
4
+
5
+ module Kontena::Cli::Services
6
+ class Stats
7
+ include Kontena::Cli::Common
8
+
9
+ def show(service_id, options)
10
+ require_api_url
11
+ token = require_token
12
+ if options.follow
13
+ system('clear')
14
+ render_header
15
+ end
16
+ loop do
17
+ fetch_stats(token, service_id, options.follow)
18
+ break unless options.follow
19
+ sleep(2)
20
+ end
21
+
22
+ end
23
+
24
+ private
25
+
26
+ def fetch_stats(token, service_id, follow)
27
+ result = client(token).get("services/#{service_id}/stats")
28
+ system('clear') if follow
29
+ render_header
30
+ result['stats'].each do |stat|
31
+ render_stat_row(stat)
32
+ end
33
+ end
34
+
35
+ def render_header
36
+ puts '%-30.30s %-15s %-20s %-15s %-15s' % ['CONTAINER', 'CPU %', 'MEM USAGE/LIMIT', 'MEM %', 'NET I/O']
37
+ end
38
+
39
+ def render_stat_row(stat)
40
+ memory = stat['memory'].nil? ? 'N/A' : filesize_to_human(stat['memory']['usage'])
41
+ if !stat['memory'].nil? && stat['memory']['limit'] != 1.8446744073709552e+19
42
+ memory_limit = filesize_to_human(stat['memory']['limit'])
43
+ memory_pct = "#{(memory.to_f / memory_limit.to_f * 100).round(2)}%"
44
+ else
45
+ memory_limit = 'N/A'
46
+ memory_pct = 'N/A'
47
+ end
48
+
49
+ cpu = stat['cpu'].nil? ? 'N/A' : stat['cpu']['usage']
50
+ network_in = stat['network'].nil? ? 'N/A' : filesize_to_human(stat['network']['rx_bytes'])
51
+ network_out = stat['network'].nil? ? 'N/A' : filesize_to_human(stat['network']['tx_bytes'])
52
+ puts '%-30.30s %-15s %-20s %-15s %-15s' % [ stat['container_id'], "#{cpu}%", "#{memory} / #{memory_limit}", "#{memory_pct}", "#{network_in}/#{network_out}"]
53
+ end
54
+ ##
55
+ # @param [String] memory
56
+ # @return [Integer]
57
+ def parse_memory(memory)
58
+ if memory.end_with?('k')
59
+ memory.to_i * 1000
60
+ elsif memory.end_with?('m')
61
+ memory.to_i * 1000000
62
+ elsif memory.end_with?('g')
63
+ memory.to_i * 1000000000
64
+ else
65
+ memory.to_i
66
+ end
67
+ end
68
+
69
+ ##
70
+ # @param [Integer] size
71
+ # @return [String]
72
+ def filesize_to_human(size)
73
+ units = %w{B K M G T}
74
+ e = (Math.log(size)/Math.log(1000)).floor
75
+ s = '%.2f' % (size.to_f / 1000**e)
76
+ s.sub(/\.?0*$/, units[e])
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,5 @@
1
+ module Kontena
2
+ module Cli
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,177 @@
1
+ require 'json'
2
+ require 'httpclient'
3
+ require_relative 'errors'
4
+ require 'kontena/cli/version'
5
+
6
+ module Kontena
7
+ class Client
8
+
9
+ attr_accessor :default_headers
10
+ attr_reader :http_client
11
+
12
+ # Initialize api client
13
+ #
14
+ # @param [String] api_url
15
+ # @param [Hash] default_headers
16
+ def initialize(api_url, default_headers = {})
17
+ @http_client = HTTPClient.new
18
+ @http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE if ignore_ssl_errors?
19
+ @default_headers = {'Accept' => 'application/json', 'Content-Type' => 'application/json', 'User-Agent' => "kontena-cli/#{Kontena::Cli::VERSION}"}.merge(default_headers)
20
+ @api_url = api_url
21
+ end
22
+
23
+ # Get request
24
+ #
25
+ # @param [String] path
26
+ # @param [Hash,NilClass] params
27
+ # @return [Hash]
28
+ def get(path, params = nil, headers = {})
29
+ response = http_client.get(request_uri(path), params, request_headers(headers))
30
+ if response.status == 200
31
+ parse_response(response)
32
+ else
33
+ handle_error_response(response)
34
+ end
35
+ end
36
+
37
+ # Post request
38
+ #
39
+ # @param [String] path
40
+ # @param [Object] obj
41
+ # @param [Hash] params
42
+ # @param [Hash] headers
43
+ # @return [Hash]
44
+ def post(path, obj, params = {}, headers = {})
45
+ request_headers = request_headers(headers)
46
+ request_options = {
47
+ header: request_headers,
48
+ body: encode_body(obj, request_headers['Content-Type']),
49
+ query: params
50
+ }
51
+
52
+ response = http_client.post(request_uri(path), request_options)
53
+ if [200, 201].include?(response.status)
54
+ parse_response(response)
55
+ else
56
+ handle_error_response(response)
57
+ end
58
+ end
59
+
60
+ # Put request
61
+ #
62
+ # @param [String] path
63
+ # @param [Object] obj
64
+ # @param [Hash] params
65
+ # @param [Hash] headers
66
+ # @return [Hash]
67
+ def put(path, obj, params = {}, headers = {})
68
+ request_headers = request_headers(headers)
69
+ request_options = {
70
+ header: request_headers,
71
+ body: encode_body(obj, request_headers['Content-Type']),
72
+ query: params
73
+ }
74
+
75
+ response = http_client.put(request_uri(path), request_options)
76
+ if [200, 201].include?(response.status)
77
+ parse_response(response)
78
+ else
79
+ handle_error_response(response)
80
+ end
81
+ end
82
+
83
+ # Delete request
84
+ #
85
+ # @param [String] path
86
+ # @param [Hash,String] body
87
+ # @param [Hash] params
88
+ # @param [Hash] headers
89
+ # @return [Hash]
90
+ def delete(path, body = nil, params = {}, headers = {})
91
+ request_headers = request_headers(headers)
92
+ request_options = {
93
+ header: request_headers,
94
+ body: encode_body(body, request_headers['Content-Type']),
95
+ query: params
96
+ }
97
+ response = http_client.delete(request_uri(path), request_options)
98
+ if response.status == 200
99
+ parse_response(response)
100
+ else
101
+ handle_error_response(response)
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ ##
108
+ # Get full request uri
109
+ #
110
+ # @param [String] path
111
+ # @return [String]
112
+ def request_uri(path)
113
+ "#{@api_url}/v1/#{path}"
114
+ end
115
+
116
+ ##
117
+ # Get request headers
118
+ #
119
+ # @param [Hash] headers
120
+ # @return [Hash]
121
+ def request_headers(headers = {})
122
+ @default_headers.merge(headers)
123
+ end
124
+
125
+ ##
126
+ # Encode body based on content type
127
+ #
128
+ # @param [Object] body
129
+ # @param [String] content_type
130
+ def encode_body(body, content_type)
131
+ if content_type == 'application/json'
132
+ dump_json(body)
133
+ else
134
+ body
135
+ end
136
+ end
137
+
138
+ ##
139
+ # Parse response
140
+ #
141
+ # @param [HTTP::Message]
142
+ # @return [Object]
143
+ def parse_response(response)
144
+ if response.headers['Content-Type'].include?('application/json')
145
+ parse_json(response.body)
146
+ else
147
+ response.body
148
+ end
149
+ end
150
+
151
+ ##
152
+ # Parse json
153
+ #
154
+ # @param [String] json
155
+ # @return [Hash,Object,NilClass]
156
+ def parse_json(json)
157
+ JSON.parse(json) rescue nil
158
+ end
159
+
160
+ ##
161
+ # Dump json
162
+ #
163
+ # @param [Object] obj
164
+ # @return [String]
165
+ def dump_json(obj)
166
+ JSON.dump(obj)
167
+ end
168
+
169
+ def ignore_ssl_errors?
170
+ ENV['SSL_IGNORE_ERRORS'] == 'true'
171
+ end
172
+
173
+ def handle_error_response(response)
174
+ raise Kontena::Errors::StandardError.new(response.status, response.body)
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,11 @@
1
+ module Kontena
2
+ module Errors
3
+ class StandardError < ::StandardError
4
+
5
+ def initialize(status, message)
6
+ @status = status
7
+ super(message)
8
+ end
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kontena-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kontena, Inc
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: httpclient
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: commander
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: inifile
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: colorize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Kontena command line tool
98
+ email:
99
+ - info@kontena.io
100
+ executables:
101
+ - kontena
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - .gitignore
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/kontena
111
+ - kontena-cli.gemspec
112
+ - lib/kontena/cli/commands.rb
113
+ - lib/kontena/cli/common.rb
114
+ - lib/kontena/cli/containers/commands.rb
115
+ - lib/kontena/cli/containers/containers.rb
116
+ - lib/kontena/cli/grids/audit_log.rb
117
+ - lib/kontena/cli/grids/commands.rb
118
+ - lib/kontena/cli/grids/grids.rb
119
+ - lib/kontena/cli/grids/users.rb
120
+ - lib/kontena/cli/nodes/commands.rb
121
+ - lib/kontena/cli/nodes/nodes.rb
122
+ - lib/kontena/cli/server/commands.rb
123
+ - lib/kontena/cli/server/server.rb
124
+ - lib/kontena/cli/server/user.rb
125
+ - lib/kontena/cli/services/commands.rb
126
+ - lib/kontena/cli/services/containers.rb
127
+ - lib/kontena/cli/services/logs.rb
128
+ - lib/kontena/cli/services/services.rb
129
+ - lib/kontena/cli/services/stats.rb
130
+ - lib/kontena/cli/version.rb
131
+ - lib/kontena/client.rb
132
+ - lib/kontena/errors.rb
133
+ homepage: http://www.kontena.io
134
+ licenses:
135
+ - Apache-2.0
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.4.3
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Kontena command line tool
157
+ test_files: []