cloudgarage-api 0.1.2 → 1.0.0

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