mms-api 0.0.9 → 0.0.10
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 +4 -4
- data/README.md +52 -59
- data/bin/mms-api +1 -146
- data/lib/mms.rb +13 -0
- data/lib/mms/agent.rb +40 -30
- data/lib/mms/cli.rb +258 -0
- data/lib/mms/client.rb +19 -37
- data/lib/mms/config.rb +57 -0
- data/lib/mms/errors.rb +41 -0
- data/lib/mms/resource.rb +28 -0
- data/lib/mms/resource/alert.rb +83 -0
- data/lib/mms/resource/cluster.rb +87 -10
- data/lib/mms/resource/group.rb +56 -9
- data/lib/mms/resource/host.rb +32 -3
- data/lib/mms/resource/restore_job.rb +45 -4
- data/lib/mms/resource/snapshot.rb +51 -10
- data/lib/mms/version.rb +1 -1
- metadata +21 -3
data/lib/mms/client.rb
CHANGED
@@ -1,49 +1,23 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
require "net/http"
|
3
|
-
require "uri"
|
4
|
-
require 'net/http/digest_auth'
|
5
|
-
require 'json'
|
6
|
-
|
7
1
|
module MMS
|
8
2
|
|
9
3
|
class Client
|
10
4
|
|
11
|
-
include Singleton
|
12
|
-
|
13
5
|
attr_accessor :username
|
14
6
|
attr_accessor :apikey
|
7
|
+
attr_accessor :url
|
15
8
|
|
16
|
-
|
17
|
-
attr_accessor :api_host
|
18
|
-
attr_accessor :api_port
|
19
|
-
attr_accessor :api_path
|
20
|
-
attr_accessor :api_version
|
21
|
-
|
22
|
-
def initialize
|
23
|
-
@username, @apikey = nil
|
24
|
-
|
25
|
-
@api_protocol = 'https'
|
26
|
-
@api_host = 'mms.mongodb.com'
|
27
|
-
@api_port = '443'
|
28
|
-
@api_path = '/api/public'
|
29
|
-
@api_version = 'v1.0'
|
30
|
-
end
|
31
|
-
|
32
|
-
def auth_setup(username, apikey)
|
9
|
+
def initialize(username = nil, apikey = nil, url = nil)
|
33
10
|
@username = username
|
34
11
|
@apikey = apikey
|
35
|
-
|
36
|
-
|
37
|
-
def site
|
38
|
-
[@api_protocol, '://', @api_host, ':', @api_port, @api_path, '/', @api_version].join.to_s
|
12
|
+
@url = url.nil? ? 'https://mms.mongodb.com:443/api/public/v1.0' : url
|
39
13
|
end
|
40
14
|
|
41
15
|
def get(path)
|
42
|
-
_get
|
16
|
+
_get(@url + path, @username, @apikey)
|
43
17
|
end
|
44
18
|
|
45
19
|
def post(path, data)
|
46
|
-
_post
|
20
|
+
_post(@url + path, data, @username, @apikey)
|
47
21
|
end
|
48
22
|
|
49
23
|
private
|
@@ -70,8 +44,12 @@ module MMS
|
|
70
44
|
response = http.request(req)
|
71
45
|
response_json = JSON.parse(response.body)
|
72
46
|
|
73
|
-
unless response_json['error'].nil?
|
74
|
-
|
47
|
+
unless response.code == 200 or response_json['error'].nil?
|
48
|
+
msg = "http 'get' error for url `#{url}`"
|
49
|
+
msg = response_json['detail'] unless response_json['detail'].nil?
|
50
|
+
|
51
|
+
raise MMS::AuthError.new(msg, req, response) if response.code == '401'
|
52
|
+
raise MMS::ApiError.new(msg, req, response)
|
75
53
|
end
|
76
54
|
|
77
55
|
(response_json.nil? or response_json['results'].nil?) ? response_json : response_json['results']
|
@@ -88,19 +66,23 @@ module MMS
|
|
88
66
|
http = Net::HTTP.new uri.host, uri.port
|
89
67
|
http.use_ssl = true
|
90
68
|
|
91
|
-
req = Net::HTTP::Post.new uri.request_uri, {'Content-Type' =>'application/json'}
|
69
|
+
req = Net::HTTP::Post.new uri.request_uri, {'Content-Type' => 'application/json'}
|
92
70
|
res = http.request req
|
93
71
|
|
94
72
|
auth = digest_auth.auth_header uri, res['WWW-Authenticate'], 'POST'
|
95
|
-
req = Net::HTTP::Post.new uri.request_uri, {'Content-Type' =>'application/json'}
|
73
|
+
req = Net::HTTP::Post.new uri.request_uri, {'Content-Type' => 'application/json'}
|
96
74
|
req.add_field 'Authorization', auth
|
97
75
|
req.body = data.to_json
|
98
76
|
|
99
77
|
response = http.request req
|
100
78
|
response_json = JSON.parse response.body
|
101
79
|
|
102
|
-
unless response_json['error'].nil?
|
103
|
-
|
80
|
+
unless response.code == 200 or response_json['error'].nil?
|
81
|
+
msg = "http 'get' error for url `#{url}`"
|
82
|
+
msg = response_json['detail'] unless response_json['detail'].nil?
|
83
|
+
|
84
|
+
raise MMS::AuthError.new(msg, req, response) if response.code == '401'
|
85
|
+
raise MMS::ApiError.new(msg, req, response)
|
104
86
|
end
|
105
87
|
|
106
88
|
(response_json.nil? or response_json['results'].nil?) ? response_json : response_json['results']
|
data/lib/mms/config.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module MMS
|
2
|
+
|
3
|
+
class Config
|
4
|
+
|
5
|
+
default = {
|
6
|
+
username: proc {
|
7
|
+
nil
|
8
|
+
},
|
9
|
+
apikey: proc {
|
10
|
+
nil
|
11
|
+
},
|
12
|
+
apiurl: proc {
|
13
|
+
[api_protocol, '://', api_host, ':', api_port, api_path, '/', api_version].join.to_s
|
14
|
+
},
|
15
|
+
limit: proc {
|
16
|
+
10
|
17
|
+
},
|
18
|
+
api_protocol: proc {
|
19
|
+
'https'
|
20
|
+
},
|
21
|
+
api_host: proc {
|
22
|
+
'mms.mongodb.com'
|
23
|
+
},
|
24
|
+
api_port: proc {
|
25
|
+
'443'
|
26
|
+
},
|
27
|
+
api_path: proc {
|
28
|
+
'/api/public'
|
29
|
+
},
|
30
|
+
api_version: proc {
|
31
|
+
'v1.0'
|
32
|
+
},
|
33
|
+
default_group_id: proc {
|
34
|
+
nil
|
35
|
+
},
|
36
|
+
default_cluster_id: proc {
|
37
|
+
nil
|
38
|
+
},
|
39
|
+
config_path: proc {
|
40
|
+
Dir.home + '/.mms-api'
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
default.each do |key, value|
|
45
|
+
define_method(key) do
|
46
|
+
if default[key].equal?(value)
|
47
|
+
default[key] = instance_eval(&value)
|
48
|
+
end
|
49
|
+
default[key]
|
50
|
+
end
|
51
|
+
define_method("#{key}=") do |value|
|
52
|
+
default[key] = value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/mms/errors.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module MMS
|
2
|
+
|
3
|
+
class RuntimeError < StandardError;
|
4
|
+
|
5
|
+
def initialize(message, request, response)
|
6
|
+
super(message)
|
7
|
+
|
8
|
+
@request = request
|
9
|
+
@response = response
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :request
|
13
|
+
attr_reader :response
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class ResourceError < StandardError
|
18
|
+
|
19
|
+
def initialize(message, resource)
|
20
|
+
super(message)
|
21
|
+
|
22
|
+
@resource = resource
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :resource
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class ApiError < RuntimeError
|
30
|
+
|
31
|
+
def initialize(message, request, response)
|
32
|
+
super("API Response error! Code: #{response.code}, body: #{response.body}", request, response)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class AuthError < RuntimeError; end
|
38
|
+
|
39
|
+
class ConfigError < StandardError; end
|
40
|
+
|
41
|
+
end
|
data/lib/mms/resource.rb
CHANGED
@@ -19,6 +19,10 @@ module MMS
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def to_hash
|
23
|
+
_to_hash
|
24
|
+
end
|
25
|
+
|
22
26
|
def reload
|
23
27
|
@data = _load(@id)
|
24
28
|
save @data unless @data.nil? or @data.empty?
|
@@ -42,5 +46,29 @@ module MMS
|
|
42
46
|
from_hash data
|
43
47
|
MMS::Cache.instance.set "Class::#{self.class.name}:#{@id}", data
|
44
48
|
end
|
49
|
+
|
50
|
+
def table_row
|
51
|
+
raise("`#{__method__}` is not implemented for `#{self.class.name}`")
|
52
|
+
end
|
53
|
+
|
54
|
+
def table_section
|
55
|
+
raise("`#{__method__}` is not implemented for `#{self.class.name}`")
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.table_header
|
59
|
+
raise("`#{__method__}` is not implemented for `#{self.class.name}`")
|
60
|
+
end
|
61
|
+
|
62
|
+
def _load(id)
|
63
|
+
raise("`#{__method__}` is not implemented for `#{self.class.name}`")
|
64
|
+
end
|
65
|
+
|
66
|
+
def _from_hash(data)
|
67
|
+
raise("`#{__method__}` is not implemented for `#{self.class.name}`")
|
68
|
+
end
|
69
|
+
|
70
|
+
def _to_hash
|
71
|
+
raise("`#{__method__}` is not implemented for `#{self.class.name}`")
|
72
|
+
end
|
45
73
|
end
|
46
74
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module MMS
|
2
|
+
|
3
|
+
class Resource::Alert < Resource
|
4
|
+
|
5
|
+
@client = nil
|
6
|
+
|
7
|
+
attr_accessor :name
|
8
|
+
attr_accessor :group
|
9
|
+
|
10
|
+
attr_accessor :type_name
|
11
|
+
attr_accessor :event_type_name
|
12
|
+
attr_accessor :status
|
13
|
+
attr_accessor :acknowledged_until
|
14
|
+
attr_accessor :created
|
15
|
+
attr_accessor :updated
|
16
|
+
attr_accessor :resolved
|
17
|
+
attr_accessor :last_notified
|
18
|
+
attr_accessor :current_value
|
19
|
+
|
20
|
+
def initialize(client, data)
|
21
|
+
id = data['id']
|
22
|
+
group_id = data['groupId']
|
23
|
+
|
24
|
+
raise MMS::ResourceError.new('`Id` for alert resource must be defined', self) if id.nil?
|
25
|
+
raise MMS::ResourceError.new('`groupId` for alert resource must be defined', self) if group_id.nil?
|
26
|
+
|
27
|
+
@client = client
|
28
|
+
|
29
|
+
@group = MMS::Resource::Group.new(client, {'id' => group_id})
|
30
|
+
|
31
|
+
super id, data
|
32
|
+
end
|
33
|
+
|
34
|
+
def ack(time, description)
|
35
|
+
data = {
|
36
|
+
:acknowledgedUntil => time,
|
37
|
+
:acknowledgementComment => description
|
38
|
+
}
|
39
|
+
alert = @client.post '/groups/' + @group.id + '/alerts/' + @id, data
|
40
|
+
!alert.nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
def table_row
|
44
|
+
[@status, @group.name, @type_name, @event_type_name, @created, @updated, @resolved, @last_notified, JSON.dump(@current_value)]
|
45
|
+
end
|
46
|
+
|
47
|
+
def table_section
|
48
|
+
rows = []
|
49
|
+
rows << table_row
|
50
|
+
rows << [{:value => "AlertId: #{@id} GroupId: #{@group.id}", :colspan => 9, :alignment => :left}]
|
51
|
+
rows << :separator
|
52
|
+
rows
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.table_header
|
56
|
+
['Status', 'Group', 'Type', 'Event name', 'Created', 'Updated', 'Resolved', 'Last notified', 'Value']
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def _load(id)
|
62
|
+
@client.get '/groups/' + @group.id + '/alerts/' + id.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def _from_hash(data)
|
66
|
+
@type_name = data['typeName']
|
67
|
+
@event_type_name = data['eventTypeName']
|
68
|
+
@status = data['status']
|
69
|
+
@acknowledged_until = data['acknowledgedUntil']
|
70
|
+
@created = data['created']
|
71
|
+
@updated = data['updated']
|
72
|
+
@resolved = data['resolved']
|
73
|
+
@last_notified = data['lastNotified']
|
74
|
+
@current_value = data['currentValue']
|
75
|
+
@name = @type_name
|
76
|
+
end
|
77
|
+
|
78
|
+
def _to_hash
|
79
|
+
@data
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
data/lib/mms/resource/cluster.rb
CHANGED
@@ -2,6 +2,8 @@ module MMS
|
|
2
2
|
|
3
3
|
class Resource::Cluster < Resource
|
4
4
|
|
5
|
+
@client = nil
|
6
|
+
|
5
7
|
attr_accessor :name
|
6
8
|
attr_accessor :group
|
7
9
|
attr_accessor :shard_name
|
@@ -12,39 +14,109 @@ module MMS
|
|
12
14
|
attr_accessor :snapshots
|
13
15
|
attr_accessor :restorejobs
|
14
16
|
|
15
|
-
def initialize(
|
17
|
+
def initialize(client, data)
|
18
|
+
id = data['id']
|
19
|
+
group_id = data['groupId']
|
20
|
+
|
21
|
+
raise MMS::ResourceError.new('`Id` for cluster resource must be defined', self) if id.nil?
|
22
|
+
raise MMS::ResourceError.new('`groupId` for cluster resource must be defined', self) if group_id.nil?
|
23
|
+
|
16
24
|
@snapshots = []
|
17
25
|
@restorejobs = []
|
18
26
|
|
19
|
-
@
|
27
|
+
@client = client
|
28
|
+
|
29
|
+
@group = MMS::Resource::Group.new(client, {'id' => group_id})
|
20
30
|
|
21
31
|
super id, data
|
22
32
|
end
|
23
33
|
|
24
34
|
def snapshot(id)
|
25
|
-
MMS::Resource::Snapshot.new id, @id, @group.id
|
35
|
+
MMS::Resource::Snapshot.new(@client, {'id' => id, 'clusterId' => @id, 'groupId' => @group.id})
|
26
36
|
end
|
27
37
|
|
28
|
-
def snapshots(page = 1, limit =
|
38
|
+
def snapshots(page = 1, limit = 10)
|
29
39
|
if @snapshots.empty?
|
30
|
-
|
31
|
-
@snapshots.push MMS::Resource::Snapshot.new(
|
40
|
+
@client.get('/groups/' + @group.id + '/clusters/' + @id + '/snapshots?pageNum=' + page.to_s + '&itemsPerPage=' + limit.to_s).each do |snapshot|
|
41
|
+
@snapshots.push MMS::Resource::Snapshot.new(@client, snapshot)
|
32
42
|
end
|
33
43
|
end
|
34
44
|
@snapshots
|
35
45
|
end
|
36
46
|
|
37
|
-
def restorejobs(page = 1, limit =
|
47
|
+
def restorejobs(page = 1, limit = 10)
|
38
48
|
if @restorejobs.empty?
|
39
|
-
|
40
|
-
|
49
|
+
@client.get('/groups/' + @group.id + '/clusters/' + @id + '/restoreJobs?pageNum=' + page.to_s + '&itemsPerPage=' + limit.to_s).each do |job|
|
50
|
+
|
51
|
+
if job['snapshotId'].nil? and job['clusterId'].nil?
|
52
|
+
raise MMS::ResourceError.new("RestoreJob `#{job['id']}` with status `#{job['statusName']}` has no `clusterId` and no `snapshotId`.", self)
|
53
|
+
elsif job['clusterId'].nil?
|
54
|
+
snapshot = @group.findSnapshot(job['snapshotId'])
|
55
|
+
job['clusterId'] = snapshot.cluster.id unless snapshot.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
@restorejobs.push MMS::Resource::RestoreJob.new(@client, job)
|
41
59
|
end
|
42
60
|
end
|
43
61
|
@restorejobs
|
44
62
|
end
|
45
63
|
|
64
|
+
def create_restorejob(point_in_time = nil)
|
65
|
+
data = {
|
66
|
+
'timestamp' => {
|
67
|
+
'date' => point_in_time,
|
68
|
+
'increment' => 0
|
69
|
+
}
|
70
|
+
}
|
71
|
+
jobs = @client.post('/groups/' + @group.id + '/clusters/' + @id + '/restoreJobs', data)
|
72
|
+
|
73
|
+
if jobs.nil?
|
74
|
+
raise MMS::ResourceError.new("Cannot create job from snapshot `#{self.id}`", self)
|
75
|
+
end
|
76
|
+
|
77
|
+
job_list = []
|
78
|
+
# work around due to bug in MMS API; cannot read restoreJob using provided info.
|
79
|
+
# The config-server RestoreJob and Snapshot has no own ClusterId to be accessed.
|
80
|
+
tries = 5
|
81
|
+
while tries > 0
|
82
|
+
begin
|
83
|
+
restore_jobs = restorejobs
|
84
|
+
tries = 0
|
85
|
+
rescue Exception => e
|
86
|
+
tries-=1;
|
87
|
+
raise MMS::ResourceError.new(e.message, self) if tries < 1
|
88
|
+
|
89
|
+
STDERR.puts e.message
|
90
|
+
STDERR.puts 'Sleeping for 5 seconds. Trying again...'
|
91
|
+
sleep(5)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
jobs.each do |job|
|
96
|
+
_list = restore_jobs.select { |restorejob| restorejob.id == job['id'] }
|
97
|
+
_list.each do |restorejob|
|
98
|
+
job_list.push restorejob
|
99
|
+
end
|
100
|
+
end
|
101
|
+
job_list
|
102
|
+
end
|
103
|
+
|
104
|
+
def table_row
|
105
|
+
[@group.name, @name, @shard_name, @replicaset_name, @type_name, @last_heartbeat, @id]
|
106
|
+
end
|
107
|
+
|
108
|
+
def table_section
|
109
|
+
[table_row]
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.table_header
|
113
|
+
['Group', 'Cluster', 'Shard name', 'Replica name', 'Type', 'Last heartbeat', 'Cluster Id']
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
46
118
|
def _load(id)
|
47
|
-
|
119
|
+
@client.get('/groups/' + @group.id + '/clusters/' + id.to_s)
|
48
120
|
end
|
49
121
|
|
50
122
|
def _from_hash(data)
|
@@ -54,5 +126,10 @@ module MMS
|
|
54
126
|
@type_name = data['typeName']
|
55
127
|
@last_heartbeat = data['lastHeartbeat']
|
56
128
|
end
|
129
|
+
|
130
|
+
def _to_hash
|
131
|
+
@data
|
132
|
+
end
|
133
|
+
|
57
134
|
end
|
58
135
|
end
|