profitbricks-sdk-ruby 1.0.2

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +202 -0
  5. data/README.md +44 -0
  6. data/Rakefile +7 -0
  7. data/docs/guide.md +223 -0
  8. data/docs/reference.md +376 -0
  9. data/lib/profitbricks/config.rb +30 -0
  10. data/lib/profitbricks/datacenter.rb +113 -0
  11. data/lib/profitbricks/firewall.rb +65 -0
  12. data/lib/profitbricks/image.rb +51 -0
  13. data/lib/profitbricks/ipblock.rb +74 -0
  14. data/lib/profitbricks/lan.rb +75 -0
  15. data/lib/profitbricks/loadbalancer.rb +126 -0
  16. data/lib/profitbricks/location.rb +28 -0
  17. data/lib/profitbricks/model.rb +116 -0
  18. data/lib/profitbricks/nic.rb +86 -0
  19. data/lib/profitbricks/profitbricks.rb +137 -0
  20. data/lib/profitbricks/request.rb +36 -0
  21. data/lib/profitbricks/server.rb +165 -0
  22. data/lib/profitbricks/snapshot.rb +78 -0
  23. data/lib/profitbricks/version.rb +3 -0
  24. data/lib/profitbricks/volume.rb +199 -0
  25. data/lib/profitbricks/wait_for.rb +16 -0
  26. data/lib/profitbricks.rb +24 -0
  27. data/profitbricks-sdk-ruby.gemspec +26 -0
  28. data/spec/datacenter_spec.rb +230 -0
  29. data/spec/firewall_spec.rb +95 -0
  30. data/spec/image_spec.rb +49 -0
  31. data/spec/ipblock_spec.rb +52 -0
  32. data/spec/lan_spec.rb +70 -0
  33. data/spec/loadbalancer_spec.rb +117 -0
  34. data/spec/location_spec.rb +20 -0
  35. data/spec/nic_spec.rb +88 -0
  36. data/spec/profitbricks_spec.rb +1 -0
  37. data/spec/request_spec.rb +37 -0
  38. data/spec/server_spec.rb +209 -0
  39. data/spec/snapshot_spec.rb +113 -0
  40. data/spec/spec_helper.rb +18 -0
  41. data/spec/support/resource_helper.rb +64 -0
  42. data/spec/volume_spec.rb +113 -0
  43. metadata +172 -0
@@ -0,0 +1,75 @@
1
+ module ProfitBricks
2
+ # LAN class
3
+ class LAN < ProfitBricks::Model
4
+
5
+ # Delete the LAN.
6
+ def delete
7
+ ProfitBricks.request(
8
+ method: :delete,
9
+ path: "/datacenters/#{self.datacenterId}/lans/#{self.id}",
10
+ expects: 202
11
+ )
12
+ end
13
+
14
+ # Update the LAN.
15
+ def update(options = {})
16
+ response = ProfitBricks.request(
17
+ method: :patch,
18
+ path: "/datacenters/#{self.datacenterId}/lans/#{self.id}",
19
+ expects: 202,
20
+ body: options.to_json
21
+ )
22
+ if response
23
+ @properties = @properties.merge(response['properties'])
24
+ end
25
+ self
26
+ end
27
+
28
+ # List LAN members.
29
+ def list_members
30
+ response = ProfitBricks.request(
31
+ method: :get,
32
+ path: "/datacenters/#{self.datacenterId}/lans/#{self.id}/nics",
33
+ expects: 200,
34
+ )
35
+ self.class.instantiate_objects(response)
36
+ end
37
+
38
+ class << self
39
+
40
+ # Create a new LAN.
41
+ def create(datacenter_id, options = {})
42
+ response = ProfitBricks.request(
43
+ method: :post,
44
+ path: "/datacenters/#{datacenter_id}/lans",
45
+ expects: 202,
46
+ body: { properties: options }.to_json
47
+ )
48
+ add_parent_identities(response)
49
+ instantiate_objects(response)
50
+ end
51
+
52
+ # List all LANs under a datacenter.
53
+ def list(datacenter_id)
54
+ response = ProfitBricks.request(
55
+ method: :get,
56
+ path: "/datacenters/#{datacenter_id}/lans",
57
+ expects: 200
58
+ )
59
+ add_parent_identities(response)
60
+ instantiate_objects(response)
61
+ end
62
+
63
+ # Retrieve a LAN under a datacenter.
64
+ def get(datacenter_id, lan_id)
65
+ response = ProfitBricks.request(
66
+ method: :get,
67
+ path: "/datacenters/#{datacenter_id}/lans/#{lan_id}",
68
+ expects: 200
69
+ )
70
+ add_parent_identities(response)
71
+ instantiate_objects(response)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,126 @@
1
+ module ProfitBricks
2
+ # Loadbalancer class
3
+ class Loadbalancer < ProfitBricks::Model
4
+ # Delete the loadbalancer.
5
+ def delete
6
+ ProfitBricks.request(
7
+ method: :delete,
8
+ path: "/datacenters/#{self.datacenterId}/loadbalancers/#{self.id}",
9
+ expects: 202
10
+ )
11
+ end
12
+
13
+ # Update the loadbalancer.
14
+ def update(options = {})
15
+ response = ProfitBricks.request(
16
+ method: :patch,
17
+ path: "/datacenters/#{self.datacenterId}/loadbalancers/#{self.id}",
18
+ expects: 202,
19
+ body: options.to_json
20
+ )
21
+ if response
22
+ @properties = @properties.merge(response['properties'])
23
+ end
24
+ self
25
+ end
26
+
27
+ def list_balanced_nics
28
+ response = ProfitBricks.request(
29
+ method: :get,
30
+ path: "/datacenters/#{self.datacenterId}/loadbalancers/#{self.id}/balancednics",
31
+ expects: 200,
32
+ )
33
+ self.class.instantiate_objects(response)
34
+ end
35
+
36
+ def associate_balanced_nic(nic_id)
37
+ response = ProfitBricks.request(
38
+ method: :post,
39
+ path: "/datacenters/#{self.datacenterId}/loadbalancers/#{self.id}/balancednics",
40
+ expects: 202,
41
+ body: { id: nic_id }.to_json
42
+ )
43
+ self.class.instantiate_objects(response)
44
+ end
45
+
46
+ def get_balanced_nic(nic_id)
47
+ response = ProfitBricks.request(
48
+ method: :get,
49
+ path: "/datacenters/#{self.datacenterId}/loadbalancers/#{self.id}/balancednics/#{nic_id}",
50
+ expects: 200
51
+ )
52
+ self.class.instantiate_objects(response)
53
+ end
54
+
55
+ def remove_balanced_nic(nic_id)
56
+ ProfitBricks.request(
57
+ method: :delete,
58
+ path: "/datacenters/#{self.datacenterId}/loadbalancers/#{self.id}/balancednics/#{nic_id}",
59
+ expects: 202
60
+ )
61
+ end
62
+
63
+ alias_method :list_nics, :list_balanced_nics
64
+ alias_method :associate_nic, :associate_balanced_nic
65
+ alias_method :remove_nic, :remove_balanced_nic
66
+
67
+ class << self
68
+ # Create a new loadbalancer.
69
+ #
70
+ # ==== Parameters
71
+ # * +options+<Hash>:
72
+ # - +name+<String> - *Optional*, name of the loadbalancer
73
+ # - +ip+<String> - *Optional*, IPv4 address of the loadbalancer
74
+ # - +dhcp+<Boolean> - *Optional*, Indicates if the loadbalancer will reserve an IP using DHCP
75
+ #
76
+ # ==== Returns
77
+ # * +id+<String> - Universally unique identifer of resource
78
+ # * +type+<String> - Resource type
79
+ # * +href+<String> - Resource URL representation
80
+ # * +metadata+<Hash>:
81
+ # - +lastModifiedDate+
82
+ # - +lastModifiedBy+
83
+ # - +createdDate+
84
+ # - +createdBy+
85
+ # - +state+
86
+ # - +etag+
87
+ # * +properties+<Hash>:
88
+ # - +name+<String>
89
+ # - +ip+<String>
90
+ # - +dhcp+<Boolean>
91
+ #
92
+ def create(datacenter_id, options = {})
93
+ response = ProfitBricks.request(
94
+ method: :post,
95
+ path: "/datacenters/#{datacenter_id}/loadbalancers",
96
+ expects: 202,
97
+ body: { properties: options }.to_json
98
+ )
99
+ add_parent_identities(response)
100
+ instantiate_objects(response)
101
+ end
102
+
103
+ # List all loadbalancers under a datacenter.
104
+ def list(datacenter_id)
105
+ response = ProfitBricks.request(
106
+ method: :get,
107
+ path: "/datacenters/#{datacenter_id}/loadbalancers",
108
+ expects: 200
109
+ )
110
+ add_parent_identities(response)
111
+ instantiate_objects(response)
112
+ end
113
+
114
+ # Retrieve a loadbalancer under a datacenter.
115
+ def get(datacenter_id, loadbalancer_id)
116
+ response = ProfitBricks.request(
117
+ method: :get,
118
+ path: "/datacenters/#{datacenter_id}/loadbalancers/#{loadbalancer_id}",
119
+ expects: 200
120
+ )
121
+ add_parent_identities(response)
122
+ instantiate_objects(response)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,28 @@
1
+ module ProfitBricks
2
+ # Location class
3
+ class Location < ProfitBricks::Model
4
+
5
+ class << self
6
+
7
+ # List all locations.
8
+ def list
9
+ response = ProfitBricks.request(
10
+ method: :get,
11
+ path: "/locations",
12
+ expects: 200
13
+ )
14
+ instantiate_objects(response)
15
+ end
16
+
17
+ # Retrieve a location.
18
+ def get(location_id)
19
+ response = ProfitBricks.request(
20
+ method: :get,
21
+ path: "/locations/#{location_id}",
22
+ expects: 200
23
+ )
24
+ instantiate_objects(response)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,116 @@
1
+ module ProfitBricks
2
+ # Resource model class
3
+ class Model
4
+ attr_accessor :metadata
5
+ attr_accessor :properties
6
+ attr_accessor :datacenterId
7
+ attr_accessor :serverId
8
+ attr_accessor :nicId
9
+ attr_accessor :requestId
10
+
11
+ def initialize(options = {})
12
+ options.each do |key, value|
13
+ self.class.send :define_method, key do
14
+ instance_variable_get("@#{key}")
15
+ end
16
+ instance_variable_set("@#{key}".to_sym, value)
17
+ end
18
+ end
19
+
20
+ def ready?
21
+ status = ProfitBricks::Request.get(self.requestId).status
22
+ status.metadata['status'] == 'DONE'
23
+ end
24
+
25
+ def reload
26
+ # Remove URL host and prefix path from href.
27
+ path = URI(self.href).path
28
+ path.sub!(ProfitBricks::Config.path_prefix, '/')
29
+
30
+ response = ProfitBricks.request(
31
+ method: :get,
32
+ path: path,
33
+ expects: 200
34
+ )
35
+
36
+ # Find cleaner method to set the variable instances on reload.
37
+ if response
38
+ if @metadata
39
+ @metadata = @metadata.merge!(response['metadata'])
40
+ else
41
+ instance_variable_set(:@metadata, response['metadata'])
42
+ end
43
+
44
+ if @properties
45
+ @properties = @properties.merge!(response['properties'])
46
+ else
47
+ instance_variable_set(:@properties, response['properties'])
48
+ end
49
+ end
50
+ self
51
+ end
52
+
53
+ def wait_for(timeout = ProfitBricks::Config.timeout, interval = 1, &block)
54
+ reload_has_succeeded = false
55
+ duration = ProfitBricks.wait_for(timeout, interval) do # Note that duration = false if it times out
56
+ # if reload
57
+ if ready?
58
+ reload_has_succeeded = true
59
+ instance_eval(&block)
60
+ else
61
+ false
62
+ end
63
+ end
64
+ if reload_has_succeeded
65
+ return duration # false if timeout; otherwise {:duration => elapsed time }
66
+ else
67
+ raise StandardError, "Reload failed, #{self.class} #{self.id} not present."
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ # Convert text to JSON.
74
+ def self.parse_json(body)
75
+ JSON.parse(body) unless body.nil? || body.empty?
76
+ rescue JSON::ParserError => error
77
+ raise error
78
+ end
79
+
80
+ # Add parent resource ID's to response resources. This will provide
81
+ # convenient ID instance variable for subsequent methods.
82
+ def self.add_parent_identities(response)
83
+ uri = URI(response['href']).path.split('/')
84
+ if response.key?('items') then
85
+ response['items'].each do |item|
86
+ item.merge!(extract_identities(uri))
87
+ end
88
+ else
89
+ response.merge!(extract_identities(uri))
90
+ end
91
+ end
92
+
93
+ def self.extract_identities(uri)
94
+ identities = {}
95
+ identities['datacenterId'] = uri[3] if uri[2] == 'datacenters'
96
+ identities['serverId'] = uri[5] if uri[4] == 'servers'
97
+ identities['nicId'] = uri[7] if uri[6] == 'nics'
98
+ identities
99
+ end
100
+
101
+ # Construct Ruby objects from API response.
102
+ def self.instantiate_objects(response)
103
+ if response['type'] == 'collection'
104
+ response['items'].map { |item| new(item) }
105
+ else
106
+ new(response)
107
+ end
108
+ end
109
+
110
+ def self.method_missing(name)
111
+ return self[name] if key? name
112
+ self.each { |key, value| return value if key.to_s.to_sym == name }
113
+ super.method_missing name
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,86 @@
1
+ module ProfitBricks
2
+ # NIC class
3
+ class NIC < ProfitBricks::Model
4
+
5
+ # Delete the NIC.
6
+ def delete
7
+ ProfitBricks.request(
8
+ method: :delete,
9
+ path: "/datacenters/#{self.datacenterId}/servers/#{self.serverId}/nics/#{self.id}",
10
+ expects: 202
11
+ )
12
+ end
13
+
14
+ # Update the NIC.
15
+ def update(options = {})
16
+ response = ProfitBricks.request(
17
+ method: :patch,
18
+ path: "/datacenters/#{self.datacenterId}/servers/#{self.serverId}/nics/#{self.id}",
19
+ expects: 202,
20
+ body: options.to_json
21
+ )
22
+ if response
23
+ @properties = @properties.merge(response['properties'])
24
+ end
25
+ self
26
+ end
27
+
28
+ # List all NIC firewall rules
29
+ def list_firewall_rules
30
+ ProfitBricks::Firewall.list(self.datacenterId, self.serverId, self.id)
31
+ end
32
+
33
+ # Retrieve NIC firewall rule
34
+ def get_firewall_rule(fwrule_id)
35
+ ProfitBricks::Firewall.get(self.datacenterId, self.serverId, self.id, fwrule_id)
36
+ end
37
+
38
+ # Create NIC firewall rule
39
+ def create_firewall_rule(options = {})
40
+ ProfitBricks::Firewall.create(self.datacenterId, self.serverId, self.id, options)
41
+ end
42
+
43
+ alias_method :list_fwrules, :list_firewall_rules
44
+ alias_method :fwrules, :list_firewall_rules
45
+ alias_method :get_fwrule, :get_firewall_rule
46
+ alias_method :fwrule, :get_firewall_rule
47
+ alias_method :create_fwrule, :create_firewall_rule
48
+
49
+ class << self
50
+
51
+ # Create a new NIC.
52
+ def create(datacenter_id, server_id, options = {})
53
+ response = ProfitBricks.request(
54
+ method: :post,
55
+ path: "/datacenters/#{datacenter_id}/servers/#{server_id}/nics",
56
+ expects: 202,
57
+ body: { properties: options }.to_json
58
+ )
59
+ add_parent_identities(response)
60
+ instantiate_objects(response)
61
+ end
62
+
63
+ # List all NICs assigned to a server.
64
+ def list(datacenter_id, server_id)
65
+ response = ProfitBricks.request(
66
+ method: :get,
67
+ path: "/datacenters/#{datacenter_id}/servers/#{server_id}/nics",
68
+ expects: 200
69
+ )
70
+ add_parent_identities(response)
71
+ instantiate_objects(response)
72
+ end
73
+
74
+ # Retrieve a NIC assigned to a datacenter.
75
+ def get(datacenter_id, server_id, nic_id)
76
+ response = ProfitBricks.request(
77
+ method: :get,
78
+ path: "/datacenters/#{datacenter_id}/servers/#{server_id}/nics/#{nic_id}",
79
+ expects: 200
80
+ )
81
+ add_parent_identities(response)
82
+ instantiate_objects(response)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,137 @@
1
+ # ProfitBricks SDK Ruby module
2
+ module ProfitBricks
3
+ def self.configure(&block)
4
+ # Configuration variable defaults
5
+ ProfitBricks::Config.timeout = 60
6
+ ProfitBricks::Config.interval = 5
7
+ ProfitBricks::Config.global_classes = true
8
+ ProfitBricks::Config.debug = false
9
+ ProfitBricks::Config.protocol = 'https'
10
+ ProfitBricks::Config.port = '443'
11
+ ProfitBricks::Config.path_prefix = '/rest/'
12
+ yield ProfitBricks::Config
13
+
14
+ if ProfitBricks::Config.host
15
+ url = construct_url
16
+ else
17
+ url = ProfitBricks::Config.url || 'https://api.profitbricks.com/rest/'
18
+ end
19
+
20
+ params = {
21
+ user: ProfitBricks::Config.username,
22
+ password: ProfitBricks::Config.password,
23
+ debug: ProfitBricks::Config.debug,
24
+ omit_default_port: true,
25
+ query: { depth: 1 }
26
+ }
27
+
28
+ @client = Excon.new(url, params)
29
+ @client
30
+
31
+ ProfitBricks.client = @client
32
+
33
+ # Flatten module namespace.
34
+ if ProfitBricks::Config.global_classes
35
+ ProfitBricks.constants.select {
36
+ |c| Class === ProfitBricks.const_get(c)
37
+ }.each do |klass|
38
+ next if klass == :Config
39
+ unless Kernel.const_defined?(klass)
40
+ Kernel.const_set(klass, ProfitBricks.const_get(klass))
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def self.request(params)
49
+ begin
50
+ params = add_headers(params)
51
+ response = ProfitBricks.client.request(prepend_path_prefix(params))
52
+ rescue Excon::Errors::Unauthorized => error
53
+ raise error, parse_json(error.response.body)['messages']
54
+ rescue Excon::Errors::HTTPStatusError => error
55
+ raise error, parse_json(error.response.body)['messages']
56
+ rescue Excon::Errors::InternalServerError => error
57
+ raise error, parse_json(error.response.body)['messages']
58
+ end
59
+ add_request_id(response)
60
+ end
61
+
62
+ def self.client=(client)
63
+ @client = client
64
+ end
65
+
66
+ def self.client
67
+ @client
68
+ end
69
+
70
+ def self.add_request_id(response)
71
+ location ||= response.headers['Location']
72
+ request_id ||= URI(location).path.split('/')[3] unless location.nil?
73
+ body = parse_json(response.body)
74
+
75
+ if body.nil?
76
+ body = { requestId: request_id }
77
+ else
78
+ body['requestId'] = request_id
79
+ end
80
+ body
81
+ end
82
+
83
+ def self.parse_json(body)
84
+ JSON.parse(body) unless body.nil? || body.empty?
85
+ rescue JSON::ParserError => error
86
+ raise error
87
+ end
88
+
89
+ def self.add_headers(params)
90
+ params[:headers] ||= {}
91
+ params[:headers].merge!(ProfitBricks::Config.headers) if ProfitBricks::Config.headers
92
+ unless params[:headers].key?('Content-Type')
93
+ params[:headers]['Content-Type'] = content_type(params[:method])
94
+ end
95
+ params
96
+ end
97
+
98
+ def self.content_type(method)
99
+ if method == :patch
100
+ 'application/vnd.profitbricks.partial-properties+json'
101
+ else
102
+ 'application/vnd.profitbricks.resource+json'
103
+ end
104
+ end
105
+
106
+ def self.prepend_path_prefix(params)
107
+ return params unless ProfitBricks::Config.path_prefix
108
+
109
+ path_prefix = ProfitBricks::Config.path_prefix.sub(/\/$/, '')
110
+ params[:path] = params[:path].sub(/^\//, '')
111
+ params[:path] = "#{path_prefix}/#{params[:path]}"
112
+ params
113
+ end
114
+
115
+ def self.construct_url
116
+ "#{ProfitBricks::Config.protocol}://" \
117
+ "#{ProfitBricks::Config.host}:" \
118
+ "#{ProfitBricks::Config.port}" \
119
+ "#{ProfitBricks::Config.path_prefix}"
120
+ end
121
+
122
+ def self.get_class(name, options = {})
123
+ klass = name.camelcase
124
+ klass = options[:class_name].to_s.camelcase if options[:class_name]
125
+ if ProfitBricks.const_defined?(klass)
126
+ klass = ProfitBricks.const_get(klass)
127
+ else
128
+ begin
129
+ require "profitbricks/#{klass.downcase}"
130
+ klass = ProfitBricks.const_get(klass)
131
+ rescue LoadError
132
+ raise LoadError.new("Invalid association, could not locate the class '#{klass}'")
133
+ end
134
+ end
135
+ klass
136
+ end
137
+ end
@@ -0,0 +1,36 @@
1
+ module ProfitBricks
2
+ # Request class
3
+ class Request < ProfitBricks::Model
4
+ # Retrieve status of a request.
5
+ def status
6
+ response = ProfitBricks.request(
7
+ method: :get,
8
+ path: "/requests/#{self.id}/status",
9
+ expects: 200
10
+ )
11
+ self.class.instantiate_objects(response)
12
+ end
13
+
14
+ class << self
15
+ # List all requests.
16
+ def list
17
+ response = ProfitBricks.request(
18
+ method: :get,
19
+ path: '/requests',
20
+ expects: 200
21
+ )
22
+ instantiate_objects(response)
23
+ end
24
+
25
+ # Retrieve a request.
26
+ def get(request_id)
27
+ response = ProfitBricks.request(
28
+ method: :get,
29
+ path: "/requests/#{request_id}",
30
+ expects: 200
31
+ )
32
+ instantiate_objects(response)
33
+ end
34
+ end
35
+ end
36
+ end