profitbricks-sdk-ruby 1.0.2

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