cloudgarage-api 0.1.2 → 1.0.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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed9846103bf204429d93058dc290bfaf654ed47e41bffecb52fe81a56806de58
4
- data.tar.gz: 0bf05055812f995cea5dc6af117ac4d990dbac38d34095b9a7da05ba625414d9
3
+ metadata.gz: 6ce5a791fca9db82814f9109112a2dd6a923d436e6478005c70f9d40c6637b2e
4
+ data.tar.gz: 1112eae2a3916e2727a5e8229ebe3d40ea7f3b870e2774ac8086223526eb4010
5
5
  SHA512:
6
- metadata.gz: 5411022bee23d99be2e61d88097ea14f16e19084524229691304b89117aaba76e6cd9cf2485588217fb9d1828ea0c079d2970754583a47367e4aa09cc1987944
7
- data.tar.gz: 288146e09da86819d8816be459a43701f356fada580083fb411920ece08e56bd7e8b20e8caee056017892720e17c1d2595b05fdb3478e7891d578fd20141d12c
6
+ metadata.gz: 50fef22aa6fe4fcbd9bdc054391aba3a4036ca1c64074ce701e3d974b9d1aa8b1b1fa054e5a9d8614410a28d3a60f17f1b2b46b95d0ae8b2c16792e6ba150cda
7
+ data.tar.gz: 15e396bbe70172a370b6c91ea997cec92a0e380eb16f77e7c2b19a9445f3612d8d518360cd5a0db5f1fa4f534cf6e8ed7cdf7da70db535a2a6158fd6947d1286
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Ruby Binding of CloudGarage Public API
1
+ # Ruby Binding and CLI of CloudGarage Public API
2
2
 
3
- A Ruby Binding of [CloudGarage Public API](https://api.cloudgarage.jp/doc/index.html).
3
+ A Ruby Binding Library and CLI of [CloudGarage Public API](https://api.cloudgarage.jp/doc/index.html).
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,21 +14,49 @@ And then execute:
14
14
 
15
15
  $ bundle
16
16
 
17
- Or install it yourself as:
17
+ Or install it yourself to use CLI as:
18
18
 
19
19
  $ gem install cloudgarage-api
20
20
 
21
- ## Usage
21
+ ## Usage of CLI (cloudgarage command)
22
22
 
23
23
  Beginning, get your API keys ('Client ID' and 'Client Secret') from the console of CloudGarage.
24
24
 
25
- ### Create client instance:
25
+ ```sh
26
+ $ cloudgarage help
27
+ Commands:
28
+ cloudgarage contracts [contract_id] # get contracts information
29
+ cloudgarage create <name> <password> [opts...] # create a server
30
+ cloudgarage delete [--notify] <server_id> # delete server
31
+ cloudgarage help [COMMAND] # Describe available commands or one specific command
32
+ cloudgarage images [os|application|private] # get images
33
+ cloudgarage keypairs [keypair_id] # get SSH Key pairs
34
+ cloudgarage login <id> <secret> # login to CloudGarage Service and get a token
35
+ cloudgarage restart [--hard] <server_id> # restart server
36
+ cloudgarage serves [server_id] # get servers information
37
+ cloudgarage start <server_id> # start server
38
+ cloudgarage stop <server_id> # stop server
39
+
40
+ Options:
41
+ [--json], [--no-json]
42
+ ```
43
+
44
+ You can get result by JSON using `--json` option for searching or querying (ex. `jq`)
45
+
46
+ ## Usage of API from ruby language
47
+
48
+ Beginning, get your API keys ('Client ID' and 'Client Secret') from the console of CloudGarage.
49
+
50
+ ### Create client instance and login:
26
51
 
27
52
  ```ruby
28
- require 'cloudgarage-api'
29
- client = CloudGarage.new(client_id, client_secret)
53
+ require 'cloudgarage/api'
54
+ client = CloudGarage::API.new
55
+ token = client.login(client_id, client_secret)
30
56
  ```
31
57
 
58
+ You can use the `token` while 24H. If the token expired, try to login again.
59
+
32
60
  ### Contract APIs
33
61
 
34
62
  ```ruby
@@ -1,7 +1,7 @@
1
1
 
2
2
  lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "cloudgarage-api/version"
4
+ require "cloudgarage/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "cloudgarage-api"
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Tada, Tadashi"]
10
10
  spec.email = ["t@tdtds.jp"]
11
11
 
12
- spec.summary = %q{CloudGarage API}
13
- spec.description = %q{Control CloudGarage VPS by it's public API}
12
+ spec.summary = %q{CloudGarage API and CLI}
13
+ spec.description = %q{Ruby Binding and CLI of CloudGarage Public API}
14
14
  spec.homepage = "https://github.com/tdtds/cloudgarage-api"
15
15
 
16
16
  # Specify which files should be added to the gem when it is released.
@@ -23,7 +23,9 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "rest-client", "~> 2.0"
26
-
26
+ spec.add_dependency "thor", "~> 0.20"
27
+ spec.add_dependency "pit"
28
+
27
29
  spec.add_development_dependency "bundler", "~> 2.0"
28
30
  spec.add_development_dependency "rake", "~> 10.0"
29
31
  spec.add_development_dependency "rspec", "~> 3.0"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'cloudgarage/cli'
3
+ CloudGarage::CLI.start
@@ -0,0 +1,142 @@
1
+ #
2
+ # A ruby wrapper of CloudGarage public API
3
+ #
4
+ # Copyright (C) 2019 by Tada, Tadashi <t@tdtds.jp>
5
+ # You can distribute under GPL 3.0
6
+ #
7
+ require 'rest-client'
8
+ require 'json'
9
+
10
+ module CloudGarage
11
+ class API
12
+ BASE_URI = 'https://api.cloudgarage.jp'.freeze
13
+
14
+ attr_accessor :token
15
+
16
+ def initialize(token = nil)
17
+ @token = token
18
+ end
19
+
20
+ def login(client_id, client_secret)
21
+ payload = {'client_id' => client_id, 'client_secret' => client_secret}
22
+ @token = post('tokens', payload)[:token][:id]
23
+ end
24
+
25
+ def contracts(contract_id = nil)
26
+ if contract_id
27
+ get("contracts/#{contract_id}")[:contract]
28
+ else
29
+ get('contracts')[:contracts]
30
+ end
31
+ end
32
+
33
+ # image_type: :os, :application, :private
34
+ def images(image_type = nil)
35
+ images = get("images")[:images]
36
+ if image_type
37
+ image_type = image_type.to_s.upcase
38
+ images.select!{|i| i[:image_type] == image_type}
39
+ end
40
+ return images
41
+ end
42
+
43
+ def keypairs(keypair_id = nil)
44
+ if keypair_id
45
+ get("keypairs/#{keypair_id}")[:keypair]
46
+ else
47
+ get('keypairs')[:keypairs]
48
+ end
49
+ end
50
+
51
+ def servers()
52
+ get('servers')[:servers]
53
+ end
54
+
55
+ def server_info(server_id)
56
+ get("servers/#{server_id}")[:server_detail]
57
+ end
58
+
59
+ def server_auto_backup_info(server_id)
60
+ get("servers/#{server_id}/autoBackup")[:autoBackup]
61
+ end
62
+
63
+ def server_security_info(server_id)
64
+ get("servers/#{server_id}/security")[:securityRules]
65
+ end
66
+
67
+ def create_server(name, password, contract_id: nil, spec: {}, ports: [], image_id: nil, keyname: nil, comment: nil)
68
+ payload = {'name' => name, 'password' => password}
69
+ payload['contract_id'] = contract_id if contract_id
70
+ payload['spec'] = spec unless spec.empty?
71
+ payload['ports'] = ports unless ports.empty?
72
+ payload['image_id'] = image_id if image_id
73
+ payload['keyname'] = keyname if keyname
74
+ payload['comment'] = comment if comment
75
+ post('servers', payload)[:resource_id]
76
+ end
77
+
78
+ # operation: :start, :restart, :restart_hard, :stop
79
+ # servers: array of server UUIDs
80
+ def operate_servers(operation, servers)
81
+ payload = {'operate' => operation.to_s.upcase, 'servers' => [servers].flatten}
82
+ post('servers/operate', payload)
83
+ end
84
+ def start_servers(servers); operate_servers(:start, servers); end
85
+ def restart_servers(servers); operate_servers(:restart, servers); end
86
+ def restart_hard_servers(servers); operate_servers(:restart_hard, servers); end
87
+ def stop_servers(servers); operate_servers(:stop, servers); end
88
+
89
+ def delete_server(resource_id, notify = true)
90
+ delete("servers/#{resource_id}?sendMail=#{notify ? 'true': 'false'}")
91
+ return true
92
+ end
93
+
94
+ def version
95
+ get("version")[:version]
96
+ end
97
+
98
+ private
99
+ def header
100
+ h = {'Content-Type' => 'application/json'}
101
+ h['X-Auth-Token'] = @token if @token
102
+ return h
103
+ end
104
+
105
+ def call_api
106
+ begin
107
+ yield
108
+ rescue RestClient::ExceptionWithResponse => ex
109
+ def ex.message
110
+ if @response
111
+ "#{default_message}: #{JSON.parse(response.body)['fault']['messages'].join(' ')}"
112
+ else
113
+ default_message
114
+ end
115
+ end
116
+ raise ex
117
+ end
118
+ end
119
+
120
+ def get(api)
121
+ call_api do
122
+ parse_body(RestClient.get("#{BASE_URI}/#{api}", header))
123
+ end
124
+ end
125
+
126
+ def post(api, payload)
127
+ call_api do
128
+ parse_body(RestClient.post("#{BASE_URI}/#{api}", payload.to_json, header))
129
+ end
130
+ end
131
+
132
+ def delete(api)
133
+ call_api do
134
+ RestClient.delete("#{BASE_URI}/#{api}", header)
135
+ end
136
+ end
137
+
138
+ def parse_body(res)
139
+ JSON.parse(res.body, symbolize_names: true)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,164 @@
1
+ require 'cloudgarage/api'
2
+ require 'thor'
3
+ require 'pit'
4
+
5
+ module CloudGarage
6
+ class CLI < Thor
7
+ class_option :json, default: false, type: :boolean # show result by json
8
+
9
+ desc 'login <id> <secret>', 'login to CloudGarage Service and get a token'
10
+ def login(client_id, client_secret)
11
+ @token = API.new.login(client_id, client_secret)
12
+ save_token(@token)
13
+ end
14
+
15
+ desc 'contracts [contract_id]', 'get contracts information'
16
+ def contracts(contract_id = nil)
17
+ call_api do |c|
18
+ c.contracts(contract_id)
19
+ end
20
+ end
21
+
22
+ desc 'images [os|application|private]', 'get images'
23
+ def images(image_type = nil)
24
+ call_api do |c|
25
+ c.images(image_type)
26
+ end
27
+ end
28
+
29
+ desc 'keypairs [keypair_id]', 'get SSH Key pairs'
30
+ def keypairs(keypair_id = nil)
31
+ call_api do |c|
32
+ c.keypairs(keypair_id)
33
+ end
34
+ end
35
+
36
+ desc 'serves [server_id]', 'get servers information'
37
+ option :backup, default: false, type: :boolean
38
+ option :security, default: false, type: :boolean
39
+ def servers(server_id = nil)
40
+ call_api do |c|
41
+ if server_id
42
+ if options[:backup]
43
+ c.server_auto_backup_info(server_id)
44
+ elsif options[:security]
45
+ c.server_security_info(server_id)
46
+ else
47
+ c.server_info(server_id)
48
+ end
49
+ else
50
+ c.servers
51
+ end
52
+ end
53
+ end
54
+
55
+ desc 'create <name> <password> [opts...]', 'create a server'
56
+ option :contract_id, default: nil, type: :string
57
+ option :spec, default: '{}', type: :string
58
+ option :ports, default: '[]', type: :string
59
+ option :image_id, default: nil, type: :string
60
+ option :keyname, default: nil, type: :string
61
+ option :comment, default: nil, type: :string
62
+ def create(name, password)
63
+ call_api do |c|
64
+ c.create_server(name, password,
65
+ contract_id: options[:contract_id],
66
+ image_id: options[:image_id],
67
+ spec: JSON.parse(options[:spec]),
68
+ ports: JSON.parse(options[:ports]),
69
+ keyname: options[:keyname],
70
+ comment: options[:comment]
71
+ )
72
+ end
73
+ end
74
+
75
+ desc 'start <server_id>', 'start server'
76
+ def start(server_id)
77
+ call_api do |c|
78
+ c.start_servers(server_id)
79
+ end
80
+ end
81
+
82
+ desc 'stop <server_id>', 'stop server'
83
+ def stop(server_id)
84
+ call_api do |c|
85
+ c.stop_servers(server_id)
86
+ end
87
+ end
88
+
89
+ desc 'restart [--hard] <server_id>', 'restart server'
90
+ option :hard, default: false, type: :boolean
91
+ def restart(server_id)
92
+ call_api do |c|
93
+ if options[:hard]
94
+ c.restart_hard_servers(server_id)
95
+ else
96
+ c.restart_servers(server_id)
97
+ end
98
+ end
99
+ end
100
+
101
+ desc 'delete [--notify] <server_id>', 'delete server'
102
+ option :notify, default: true, type: :boolean
103
+ def delete(server_id)
104
+ call_api do |c|
105
+ c.delete_server(server_id, options[:notify])
106
+ return nil
107
+ end
108
+ end
109
+
110
+ private
111
+ CREDENTIAL_KEY = 'api.cloudgarage.jp'
112
+ def load_token
113
+ Pit::get(CREDENTIAL_KEY)[:token]
114
+ end
115
+
116
+ def save_token(token)
117
+ Pit::set(CREDENTIAL_KEY, data: {token: token})
118
+ end
119
+
120
+ def client
121
+ @token = load_token unless @token
122
+ API.new(@token)
123
+ end
124
+
125
+ def refresh_token
126
+ if $stdin.tty? && $stdout.tty?
127
+ begin
128
+ puts 'Access tokens expired, enter your Client ID and Secret.'
129
+ print 'Client ID: '
130
+ client_id = $stdin.gets.chomp
131
+ print 'Client Secret: '
132
+ client_secret = $stdin.gets.chomp
133
+ login(client_id, client_secret)
134
+ rescue Interrupt
135
+ exit 255
136
+ rescue
137
+ $stderr.puts "Could not login. try again."
138
+ exit 255
139
+ end
140
+ else
141
+ $stderr.puts "Access tokens expired. try login again."
142
+ exit 255
143
+ end
144
+ end
145
+
146
+ def call_api
147
+ begin
148
+ result = yield(client)
149
+ if options[:json]
150
+ puts result.to_json if result
151
+ else
152
+ pp result if result
153
+ end
154
+ exit 0
155
+ rescue RestClient::Unauthorized => e
156
+ refresh_token
157
+ retry
158
+ rescue => e
159
+ $stderr.puts e.message
160
+ exit 255
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,3 @@
1
+ module CloudGarage
2
+ VERSION = "1.0.0".freeze
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudgarage-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tada, Tadashi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-12 00:00:00.000000000 Z
11
+ date: 2019-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.20'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.20'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,10 +122,11 @@ dependencies:
94
122
  - - ">="
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0'
97
- description: Control CloudGarage VPS by it's public API
125
+ description: Ruby Binding and CLI of CloudGarage Public API
98
126
  email:
99
127
  - t@tdtds.jp
100
- executables: []
128
+ executables:
129
+ - cloudgarage
101
130
  extensions: []
102
131
  extra_rdoc_files: []
103
132
  files:
@@ -111,8 +140,10 @@ files:
111
140
  - bin/console
112
141
  - bin/setup
113
142
  - cloudgarage-api.gemspec
114
- - lib/cloudgarage-api.rb
115
- - lib/cloudgarage-api/version.rb
143
+ - exe/cloudgarage
144
+ - lib/cloudgarage/api.rb
145
+ - lib/cloudgarage/cli.rb
146
+ - lib/cloudgarage/version.rb
116
147
  homepage: https://github.com/tdtds/cloudgarage-api
117
148
  licenses: []
118
149
  metadata: {}
@@ -134,5 +165,5 @@ requirements: []
134
165
  rubygems_version: 3.0.1
135
166
  signing_key:
136
167
  specification_version: 4
137
- summary: CloudGarage API
168
+ summary: CloudGarage API and CLI
138
169
  test_files: []
@@ -1,137 +0,0 @@
1
- #
2
- # A ruby wrapper of CloudGarage public API
3
- #
4
- # Copyright (C) 2019 by Tada, Tadashi <t@tdtds.jp>
5
- # You can distribute under GPL 3.0
6
- #
7
- require 'rest-client'
8
-
9
- class CloudGarage
10
- BASE_URI = 'https://api.cloudgarage.jp'.freeze
11
-
12
- def initialize(client_id, client_secret)
13
- @client_id, @client_secret = client_id, client_secret
14
- token
15
- end
16
-
17
- def token
18
- payload = {'client_id' => @client_id, 'client_secret' => @client_secret}
19
- @token = post('tokens', payload)[:token][:id]
20
- end
21
-
22
- def contracts(contract_id = nil)
23
- if contract_id
24
- get("contracts/#{contract_id}")[:contract]
25
- else
26
- get('contracts')[:contracts]
27
- end
28
- end
29
-
30
- # image_type: :os, :application, :private
31
- def images(image_type = nil)
32
- images = get("images")[:images]
33
- if image_type
34
- image_type = image_type.to_s.upcase
35
- images.select!{|i| i[:image_type] == image_type}
36
- end
37
- return images
38
- end
39
-
40
- def keypairs(keypair_id = nil)
41
- if keypair_id
42
- get("keypairs/#{keypair_id}")[:keypair]
43
- else
44
- get('keypairs')[:keypairs]
45
- end
46
- end
47
-
48
- def servers()
49
- get('servers')[:servers]
50
- end
51
-
52
- def server_info(server_id)
53
- get("servers/#{server_id}")[:server_detail]
54
- end
55
-
56
- def server_auto_backup_info(server_id)
57
- get("servers/#{server_id}/autoBackup")[:autoBackup]
58
- end
59
-
60
- def server_security_info(server_id)
61
- get("servers/#{server_id}/security")[:securityRules]
62
- end
63
-
64
- def create_server(name, password, contract_id: nil, spec: {}, ports: [], image_id: nil, keyname: nil, comment: nil)
65
- payload = {'name' => name, 'password' => password}
66
- payload['contract_id'] = contract_id if contract_id
67
- payload['spec'] = spec unless spec.empty?
68
- payload['ports'] = ports unless ports.empty?
69
- payload['image_id'] = image_id if image_id
70
- payload['keyname'] = keyname if keyname
71
- payload['comment'] = comment if comment
72
- post('servers', payload)[:resource_id]
73
- end
74
-
75
- # operation: :start, :restart, :restart_hard, :stop
76
- # servers: array of server UUIDs
77
- def operate_servers(operation, servers)
78
- payload = {'operate' => operation.to_s.upcase, 'servers' => [servers].flatten}
79
- post('servers/operate', payload)
80
- end
81
- def start_servers(servers); operate_servers(:start, servers); end
82
- def restart_servers(servers); operate_servers(:restart, servers); end
83
- def restart_hard_servers(servers); operate_servers(:restart_hard, servers); end
84
- def stop_servers(servers); operate_servers(:stop, servers); end
85
-
86
- def delete_server(resource_id, notify = true)
87
- delete("servers/#{resource_id}?sendMail=#{notify ? 'true': 'false'}")
88
- end
89
-
90
- def version
91
- get("version")[:version]
92
- end
93
-
94
- private
95
- def header
96
- h = {'Content-Type' => 'application/json'}
97
- h['X-Auth-Token'] = @token if @token
98
- return h
99
- end
100
-
101
- def call_api
102
- begin
103
- yield
104
- rescue RestClient::ExceptionWithResponse => ex
105
- def ex.message
106
- if @response
107
- "#{default_message}: #{JSON.parse(response.body)['fault']['messages'].join(' ')}"
108
- else
109
- default_message
110
- end
111
- end
112
- raise ex
113
- end
114
- end
115
-
116
- def get(api)
117
- call_api do
118
- parse_body(RestClient.get("#{BASE_URI}/#{api}", header))
119
- end
120
- end
121
-
122
- def post(api, payload)
123
- call_api do
124
- parse_body(RestClient.post("#{BASE_URI}/#{api}", payload.to_json, header))
125
- end
126
- end
127
-
128
- def delete(api)
129
- call_api do
130
- RestClient.delete("#{BASE_URI}/#{api}", header)
131
- end
132
- end
133
-
134
- def parse_body(res)
135
- JSON.parse(res.body, symbolize_names: true)
136
- end
137
- end
@@ -1,3 +0,0 @@
1
- class CloudGarage
2
- VERSION = "0.1.2".freeze
3
- end