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.
@@ -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
- attr_accessor :api_protocol
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
- end
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 site + path, @username, @apikey
16
+ _get(@url + path, @username, @apikey)
43
17
  end
44
18
 
45
19
  def post(path, data)
46
- _post site + path, data, @username, @apikey
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
- response_json = nil
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
- response_json = nil
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']
@@ -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
@@ -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
@@ -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
@@ -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(id, group_id, data = nil)
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
- @group = MMS::Resource::Group.new(group_id)
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 = 1000)
38
+ def snapshots(page = 1, limit = 10)
29
39
  if @snapshots.empty?
30
- MMS::Client.instance.get('/groups/' + @group.id + '/clusters/' + @id + '/snapshots?pageNum=' + page.to_s + '&itemsPerPage=' + limit.to_s).each do |snapshot|
31
- @snapshots.push MMS::Resource::Snapshot.new(snapshot['id'], snapshot['clusterId'], snapshot['groupId'], snapshot)
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 = 1000)
47
+ def restorejobs(page = 1, limit = 10)
38
48
  if @restorejobs.empty?
39
- MMS::Client.instance.get('/groups/' + @group.id + '/clusters/' + @id + '/restoreJobs?pageNum=' + page.to_s + '&itemsPerPage=' + limit.to_s).each do |job|
40
- @restorejobs.push MMS::Resource::RestoreJob.new(job['id'], job['clusterId'], job['groupId'], job)
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
- MMS::Client.instance.get '/groups/' + @group.id + '/clusters/' + id.to_s
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