mms-api 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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