openshift-origin-controller 1.3.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 (180) hide show
  1. data/COPYRIGHT +1 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +12 -0
  4. data/README.md +3 -0
  5. data/Rakefile +9 -0
  6. data/app/controllers/app_events_controller.rb +115 -0
  7. data/app/controllers/application_templates_controller.rb +19 -0
  8. data/app/controllers/applications_controller.rb +214 -0
  9. data/app/controllers/base_controller.rb +367 -0
  10. data/app/controllers/cartridges_controller.rb +48 -0
  11. data/app/controllers/descriptors_controller.rb +23 -0
  12. data/app/controllers/dns_resolvable_controller.rb +35 -0
  13. data/app/controllers/domains_controller.rb +156 -0
  14. data/app/controllers/emb_cart_controller.rb +276 -0
  15. data/app/controllers/emb_cart_events_controller.rb +52 -0
  16. data/app/controllers/environment_controller.rb +11 -0
  17. data/app/controllers/estimates_controller.rb +71 -0
  18. data/app/controllers/gear_groups_controller.rb +53 -0
  19. data/app/controllers/gears_controller.rb +70 -0
  20. data/app/controllers/keys_controller.rb +96 -0
  21. data/app/controllers/legacy_broker_controller.rb +510 -0
  22. data/app/controllers/quickstarts_controller.rb +29 -0
  23. data/app/controllers/user_controller.rb +38 -0
  24. data/app/helpers/cartridge_helper.rb +25 -0
  25. data/app/helpers/legacy_broker_helper.rb +21 -0
  26. data/app/helpers/user_action_logger.rb +38 -0
  27. data/app/models/application.rb +1718 -0
  28. data/app/models/application_template.rb +27 -0
  29. data/app/models/cartridge_cache.rb +51 -0
  30. data/app/models/cloud_user.rb +334 -0
  31. data/app/models/component_instance.rb +228 -0
  32. data/app/models/connection_endpoint.rb +10 -0
  33. data/app/models/district.rb +210 -0
  34. data/app/models/domain.rb +234 -0
  35. data/app/models/gear.rb +376 -0
  36. data/app/models/group_instance.rb +306 -0
  37. data/app/models/key.rb +20 -0
  38. data/app/models/legacy_reply.rb +15 -0
  39. data/app/models/legacy_request.rb +126 -0
  40. data/app/models/link.rb +11 -0
  41. data/app/models/message.rb +10 -0
  42. data/app/models/name_server_cache.rb +46 -0
  43. data/app/models/optional_param.rb +12 -0
  44. data/app/models/param.rb +13 -0
  45. data/app/models/remote_job.rb +57 -0
  46. data/app/models/rest_application.rb +126 -0
  47. data/app/models/rest_application10.rb +106 -0
  48. data/app/models/rest_application12.rb +124 -0
  49. data/app/models/rest_application_estimate.rb +12 -0
  50. data/app/models/rest_application_template.rb +20 -0
  51. data/app/models/rest_cartridge10.rb +41 -0
  52. data/app/models/rest_cartridge11.rb +151 -0
  53. data/app/models/rest_domain.rb +43 -0
  54. data/app/models/rest_domain10.rb +42 -0
  55. data/app/models/rest_estimates.rb +16 -0
  56. data/app/models/rest_gear.rb +14 -0
  57. data/app/models/rest_gear_group.rb +26 -0
  58. data/app/models/rest_key.rb +24 -0
  59. data/app/models/rest_reply.rb +31 -0
  60. data/app/models/rest_user.rb +43 -0
  61. data/app/models/result_io.rb +67 -0
  62. data/app/models/usage_record.rb +37 -0
  63. data/app/models/validators/app_validator.rb +30 -0
  64. data/app/models/validators/key_validator.rb +30 -0
  65. data/app/models/validators/namespace_validator.rb +18 -0
  66. data/config/routes.rb +36 -0
  67. data/lib/controller_engine.rb +7 -0
  68. data/lib/openshift-origin-controller.rb +14 -0
  69. data/lib/openshift/application_container_proxy.rb +241 -0
  70. data/lib/openshift/auth_service.rb +101 -0
  71. data/lib/openshift/data_store.rb +33 -0
  72. data/lib/openshift/dns_service.rb +41 -0
  73. data/lib/openshift/mongo_data_store.rb +671 -0
  74. data/openshift-origin-controller.gemspec +42 -0
  75. data/rubygem-openshift-origin-controller.spec +274 -0
  76. data/test/cucumber/application-estimate.feature +25 -0
  77. data/test/cucumber/cartridge-10gen-mms-agent.feature +28 -0
  78. data/test/cucumber/cartridge-cron.feature +32 -0
  79. data/test/cucumber/cartridge-haproxy.feature +31 -0
  80. data/test/cucumber/cartridge-jenkins-build.feature +12 -0
  81. data/test/cucumber/cartridge-jenkins-client.feature +10 -0
  82. data/test/cucumber/cartridge-lifecycle-diy.feature +21 -0
  83. data/test/cucumber/cartridge-lifecycle-jbossas.feature +61 -0
  84. data/test/cucumber/cartridge-lifecycle-jbosseap.feature +61 -0
  85. data/test/cucumber/cartridge-lifecycle-jbossews10.feature +61 -0
  86. data/test/cucumber/cartridge-lifecycle-jenkins.feature +41 -0
  87. data/test/cucumber/cartridge-lifecycle-nodejs.feature +59 -0
  88. data/test/cucumber/cartridge-lifecycle-perl.feature +40 -0
  89. data/test/cucumber/cartridge-lifecycle-php.feature +106 -0
  90. data/test/cucumber/cartridge-lifecycle-python.feature +40 -0
  91. data/test/cucumber/cartridge-lifecycle-ruby18.feature +49 -0
  92. data/test/cucumber/cartridge-lifecycle-ruby19.feature +41 -0
  93. data/test/cucumber/cartridge-mongodb.feature +31 -0
  94. data/test/cucumber/cartridge-mysql.feature +30 -0
  95. data/test/cucumber/cartridge-php.feature +14 -0
  96. data/test/cucumber/cartridge-phpmyadmin.feature +32 -0
  97. data/test/cucumber/cartridge-postgresql.feature +32 -0
  98. data/test/cucumber/cartridge-runtime-extended-db.feature +64 -0
  99. data/test/cucumber/cartridge-runtime-extended-jboss.feature +24 -0
  100. data/test/cucumber/cartridge-runtime-extended-nodejs.feature +21 -0
  101. data/test/cucumber/cartridge-runtime-extended-perl.feature +18 -0
  102. data/test/cucumber/cartridge-runtime-extended-php.feature +19 -0
  103. data/test/cucumber/cartridge-runtime-extended-python.feature +18 -0
  104. data/test/cucumber/cartridge-runtime-extended-ruby.feature +22 -0
  105. data/test/cucumber/cartridge-runtime-standard-diy.feature +6 -0
  106. data/test/cucumber/cartridge-runtime-standard-jbossas.feature +7 -0
  107. data/test/cucumber/cartridge-runtime-standard-jbosseap.feature +7 -0
  108. data/test/cucumber/cartridge-runtime-standard-jbossews10.feature +7 -0
  109. data/test/cucumber/cartridge-runtime-standard-jenkins.feature +8 -0
  110. data/test/cucumber/cartridge-runtime-standard-nodejs.feature +7 -0
  111. data/test/cucumber/cartridge-runtime-standard-perl.feature +6 -0
  112. data/test/cucumber/cartridge-runtime-standard-php.feature +6 -0
  113. data/test/cucumber/cartridge-runtime-standard-python.feature +6 -0
  114. data/test/cucumber/cartridge-runtime-standard-ruby.feature +19 -0
  115. data/test/cucumber/cartridge-switchyard.feature +36 -0
  116. data/test/cucumber/descriptor.feature +40 -0
  117. data/test/cucumber/embedded.feature +44 -0
  118. data/test/cucumber/idler.feature +75 -0
  119. data/test/cucumber/misc/descriptor/manifest.yml +22 -0
  120. data/test/cucumber/misc/php/db_test.php +21 -0
  121. data/test/cucumber/openshift-node.feature +21 -0
  122. data/test/cucumber/rest-application-templates.feature +31 -0
  123. data/test/cucumber/rest-applications.feature +431 -0
  124. data/test/cucumber/rest-cartridge-types.feature +16 -0
  125. data/test/cucumber/rest-domains.feature +276 -0
  126. data/test/cucumber/rest-gears.feature +38 -0
  127. data/test/cucumber/rest-keys.feature +247 -0
  128. data/test/cucumber/rest-quickstarts.feature +27 -0
  129. data/test/cucumber/rest-workflow.feature +64 -0
  130. data/test/cucumber/step_definitions/api_steps.rb +369 -0
  131. data/test/cucumber/step_definitions/application-estimate-steps.rb +51 -0
  132. data/test/cucumber/step_definitions/application_steps.rb +215 -0
  133. data/test/cucumber/step_definitions/cartridge-10gen-mms-agent_steps.rb +11 -0
  134. data/test/cucumber/step_definitions/cartridge-cron_steps.rb +51 -0
  135. data/test/cucumber/step_definitions/cartridge-haproxy_steps.rb +30 -0
  136. data/test/cucumber/step_definitions/cartridge-jenkins_steps.rb +93 -0
  137. data/test/cucumber/step_definitions/cartridge-lifecycle-nodejs_steps.rb +30 -0
  138. data/test/cucumber/step_definitions/cartridge-mongodb_steps.rb +60 -0
  139. data/test/cucumber/step_definitions/cartridge-mysql_steps.rb +56 -0
  140. data/test/cucumber/step_definitions/cartridge-php_steps.rb +72 -0
  141. data/test/cucumber/step_definitions/cartridge-postgresql_steps.rb +59 -0
  142. data/test/cucumber/step_definitions/cartridge-switchyard_steps.rb +29 -0
  143. data/test/cucumber/step_definitions/client_steps.rb +12 -0
  144. data/test/cucumber/step_definitions/descriptor_step.rb +32 -0
  145. data/test/cucumber/step_definitions/idler_steps.rb +37 -0
  146. data/test/cucumber/step_definitions/node_steps.rb +203 -0
  147. data/test/cucumber/step_definitions/runtime_steps.rb +547 -0
  148. data/test/cucumber/step_definitions/runtime_url_steps.rb +46 -0
  149. data/test/cucumber/step_definitions/trap-user-extended_steps.rb +14 -0
  150. data/test/cucumber/step_definitions/trap-user_steps.rb +58 -0
  151. data/test/cucumber/support/00_setup_helper.rb +106 -0
  152. data/test/cucumber/support/app_helper.rb +243 -0
  153. data/test/cucumber/support/assertions.rb +52 -0
  154. data/test/cucumber/support/command_helper.rb +453 -0
  155. data/test/cucumber/support/dns_helper.rb +54 -0
  156. data/test/cucumber/support/env.rb +5 -0
  157. data/test/cucumber/support/process_helper.rb +44 -0
  158. data/test/cucumber/support/runtime_support.rb +440 -0
  159. data/test/cucumber/support/unused.rb +27 -0
  160. data/test/cucumber/support/user_helper.rb +37 -0
  161. data/test/cucumber/trap-user-extended.feature +53 -0
  162. data/test/cucumber/trap-user.feature +34 -0
  163. data/test/ddns/1.168.192-rev.db.init +13 -0
  164. data/test/ddns/HOWTO.txt +207 -0
  165. data/test/ddns/Kexample.com.+157+06142.key +1 -0
  166. data/test/ddns/Kexample.com.+157+06142.private +7 -0
  167. data/test/ddns/authconfig.rb +14 -0
  168. data/test/ddns/example.com.db.init +23 -0
  169. data/test/ddns/example.com.key +4 -0
  170. data/test/ddns/named.ca +52 -0
  171. data/test/ddns/named.conf +48 -0
  172. data/test/ddns/named.empty +10 -0
  173. data/test/ddns/named.localhost +10 -0
  174. data/test/ddns/named.loopback +11 -0
  175. data/test/ddns/named.rfc1912.zones +42 -0
  176. data/test/ddns/named.root.key +5 -0
  177. data/test/ddns/named_service.rb +127 -0
  178. data/test/unit/bind_dns_service_test.rb +167 -0
  179. data/test/unit/broker_auth_test.rb +28 -0
  180. metadata +545 -0
@@ -0,0 +1,7 @@
1
+ require 'openshift-origin-controller'
2
+ require 'rails'
3
+
4
+ module OpenShift
5
+ class CloudEngine < ::Rails::Engine
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require "openshift-origin-common"
2
+
3
+ module OpenShift
4
+ module Controller
5
+ require 'controller_engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
6
+ end
7
+ end
8
+
9
+ #require "cloud_user"
10
+ require "openshift/application_container_proxy"
11
+ require "openshift/auth_service"
12
+ require "openshift/dns_service"
13
+ require "openshift/data_store"
14
+ require "openshift/mongo_data_store"
@@ -0,0 +1,241 @@
1
+ module OpenShift
2
+ class ApplicationContainerProxy
3
+ @proxy_provider = OpenShift::ApplicationContainerProxy
4
+
5
+ def self.valid_gear_sizes(user)
6
+ @proxy_provider.valid_gear_sizes_impl(user)
7
+ end
8
+
9
+ def self.valid_gear_sizes_impl(user)
10
+ return ["small"]
11
+ end
12
+
13
+ def self.provider=(provider_class)
14
+ @proxy_provider = provider_class
15
+ end
16
+
17
+ def self.instance(id)
18
+ @proxy_provider.new(id)
19
+ end
20
+
21
+ def self.find_available(node_profile=nil)
22
+ @proxy_provider.find_available_impl(node_profile)
23
+ end
24
+
25
+ def self.find_one(node_profile=nil)
26
+ @proxy_provider.find_one_impl(node_profile)
27
+ end
28
+
29
+ def self.get_blacklisted
30
+ @proxy_provider.get_blacklisted_in_impl
31
+ end
32
+
33
+ def self.get_blacklisted_in_impl
34
+ []
35
+ end
36
+
37
+
38
+ def self.blacklisted?(name)
39
+ @proxy_provider.blacklisted_in_impl?(name)
40
+ end
41
+
42
+ def self.blacklisted_in_impl?(name)
43
+ end
44
+
45
+ def self.get_all_gears
46
+ @proxy_provider.get_all_gears_impl
47
+ end
48
+
49
+ def self.get_all_gears_impl
50
+ end
51
+
52
+ def self.get_all_active_gears
53
+ @proxy_provider.get_all_active_gears_impl
54
+ end
55
+
56
+ def self.get_all_active_gears_impl
57
+ end
58
+
59
+ def self.execute_parallel_jobs(handle)
60
+ @proxy_provider.execute_parallel_jobs_impl(handle)
61
+ end
62
+
63
+ def self.execute_parallel_jobs_impl(handle)
64
+ end
65
+
66
+ attr_accessor :id
67
+ def self.find_available_impl(node_profile=nil)
68
+ end
69
+
70
+ def self.find_one_impl(node_profile=nil)
71
+ end
72
+
73
+ def reserve_uid
74
+ end
75
+
76
+ def unreserve_uid(uid)
77
+ end
78
+
79
+ def get_available_cartridges
80
+ end
81
+
82
+ def create(app, gear)
83
+ end
84
+
85
+ def destroy(app, gear)
86
+ end
87
+
88
+ def add_authorized_ssh_key(app, gear, ssh_key, key_type=nil, comment=nil)
89
+ end
90
+
91
+ def remove_authorized_ssh_key(app, gear, ssh_key, comment=nil)
92
+ end
93
+
94
+ def add_env_var(app, gear, key, value)
95
+ end
96
+
97
+ def remove_env_var(app, gear, key)
98
+ end
99
+
100
+ def add_broker_auth_key(app, gear, iv, token)
101
+ end
102
+
103
+ def remove_broker_auth_key(app, gear)
104
+ end
105
+
106
+ def show_state(app, gear)
107
+ end
108
+
109
+ def configure_cartridge(app, gear, cart, template_git_url=nil)
110
+ end
111
+
112
+ def deconfigure_cartridge(app, gear, cart)
113
+ end
114
+
115
+ def get_public_hostname
116
+ end
117
+
118
+ def get_quota_blocks
119
+ end
120
+
121
+ def get_quota_files
122
+ end
123
+
124
+ def execute_connector(app, gear, cart, connector_name, input_args)
125
+ end
126
+
127
+ def start(app, gear, cart)
128
+ end
129
+
130
+ def stop(app, gear, cart)
131
+ end
132
+
133
+ def force_stop(app, gear, cart)
134
+ end
135
+
136
+ def restart(app, gear, cart)
137
+ end
138
+
139
+ def reload(app, gear, cart)
140
+ end
141
+
142
+ def status(app, gear, cart)
143
+ end
144
+
145
+ def tidy(app, gear, cart)
146
+ end
147
+
148
+ def threaddump(app, gear, cart)
149
+ end
150
+
151
+ def system_messages(app, gear, cart)
152
+ end
153
+
154
+ def expose_port(app, gear, cart)
155
+ end
156
+
157
+ def conceal_port(app, gear, cart)
158
+ end
159
+
160
+ def show_port(app, gear, cart)
161
+ end
162
+
163
+ def add_alias(app, gear, server_alias)
164
+ end
165
+
166
+ def remove_alias(app, gear, server_alias)
167
+ end
168
+
169
+ def update_namespace(app, cart, new_ns, old_ns)
170
+ end
171
+
172
+ def get_quota(gear)
173
+ end
174
+
175
+ def set_quota(gear, storage_in_gb, inodes)
176
+ end
177
+
178
+ def framework_carts
179
+ end
180
+
181
+ def embedded_carts
182
+ end
183
+
184
+ def add_component(app, gear, component)
185
+ end
186
+
187
+ def remove_component(app, gear, component)
188
+ end
189
+
190
+ def start_component(app, gear, component)
191
+ end
192
+
193
+ def stop_component(app, gear, component)
194
+ end
195
+
196
+ def restart_component(app, gear, component)
197
+ end
198
+
199
+ def reload_component(app, gear, component)
200
+ end
201
+
202
+ def component_status(app, gear, component)
203
+ end
204
+
205
+ def has_app?(app_uuid, app_name)
206
+ end
207
+
208
+ def has_embedded_app?(app_uuid, embedded_type)
209
+ end
210
+
211
+ def get_env_var_add_job(app, gear, key, value)
212
+ end
213
+
214
+ def get_env_var_remove_job(app, gear, key)
215
+ end
216
+
217
+ def get_add_authorized_ssh_key_job(app, gear, ssh_key, key_type=nil, comment=nil)
218
+ end
219
+
220
+ def get_remove_authorized_ssh_key_job(app, gear, ssh_key, comment=nil)
221
+ end
222
+
223
+ def get_execute_connector_job(app, gear, cart, connector_name, input_args)
224
+ end
225
+
226
+ def get_broker_auth_key_add_job(app, gear, iv, token)
227
+ end
228
+
229
+ def get_broker_auth_key_remove_job(app, gear)
230
+ end
231
+
232
+ def get_show_state_job(app, gear)
233
+ end
234
+
235
+ def get_show_gear_quota_job(gear)
236
+ end
237
+
238
+ def get_update_gear_quota_job(gear, storage_in_gb, inodes)
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,101 @@
1
+ require 'digest/md5'
2
+
3
+ module OpenShift
4
+ class AuthService
5
+ @oo_auth_provider = OpenShift::AuthService
6
+
7
+ def self.provider=(provider_class)
8
+ @oo_auth_provider = provider_class
9
+ end
10
+
11
+ def self.instance
12
+ @oo_auth_provider.new
13
+ end
14
+
15
+ def initialize(auth_info = nil)
16
+ # This is useful for testing
17
+ @auth_info = auth_info
18
+
19
+ if @auth_info.nil?
20
+ @auth_info = Rails.application.config.auth
21
+ end
22
+
23
+ @salt = @auth_info[:salt]
24
+ @privkeyfile = @auth_info[:privkeyfile]
25
+ @privkeypass = @auth_info[:privkeypass]
26
+ @pubkeyfile = @auth_info[:pubkeyfile]
27
+
28
+ @token_login_key = @auth_info[:token_login_key] || :login
29
+ end
30
+
31
+ # Be careful overriding this method in a subclass. Doing so incorrectly
32
+ # can break node->broker authentication when swapping plugins.
33
+ def generate_broker_key(app)
34
+ cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
35
+ cipher.encrypt
36
+ cipher.key = OpenSSL::Digest::SHA512.new(@salt).digest
37
+ cipher.iv = iv = cipher.random_iv
38
+ token = {:app_name => app.name,
39
+ @token_login_key => app.user.login,
40
+ :creation_time => app.creation_time}
41
+ encrypted_token = cipher.update(token.to_json)
42
+ encrypted_token << cipher.final
43
+
44
+ public_key = OpenSSL::PKey::RSA.new(File.read(@pubkeyfile), @privkeypass)
45
+ encrypted_iv = public_key.public_encrypt(iv)
46
+
47
+ # Base64 encode the iv and token
48
+ encoded_iv = Base64::encode64(encrypted_iv)
49
+ encoded_token = Base64::encode64(encrypted_token)
50
+
51
+ [encoded_iv, encoded_token]
52
+ end
53
+
54
+ # Be careful overriding this method in a subclass. Doing so incorrectly
55
+ # can break node->broker authentication when swapping plugins.
56
+ def validate_broker_key(iv, key)
57
+ key = key.gsub(" ", "+")
58
+ iv = iv.gsub(" ", "+")
59
+ begin
60
+ encrypted_token = Base64::decode64(key)
61
+ cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
62
+ cipher.decrypt
63
+ cipher.key = OpenSSL::Digest::SHA512.new(@salt).digest
64
+ private_key = OpenSSL::PKey::RSA.new(File.read(@privkeyfile), @privkeypass)
65
+ cipher.iv = private_key.private_decrypt(Base64::decode64(iv))
66
+ json_token = cipher.update(encrypted_token)
67
+ json_token << cipher.final
68
+ rescue => e
69
+ $stderr.puts e.message
70
+ $stderr.puts e.backtrace
71
+ Rails.logger.debug "Broker key authentication failed. #{e.backtrace.inspect}"
72
+ raise OpenShift::AccessDeniedException.new
73
+ end
74
+
75
+ token = JSON.parse(json_token)
76
+ username = token[@token_login_key.to_s]
77
+ app_name = token['app_name']
78
+ creation_time = token['creation_time']
79
+
80
+ user = CloudUser.find(username)
81
+ raise OpenShift::AccessDeniedException.new if user.nil?
82
+ app = Application.find(user, app_name)
83
+
84
+ raise OpenShift::AccessDeniedException.new if app.nil? or creation_time != app.creation_time
85
+ return {:username => username, :auth_method => :broker_auth}
86
+ end
87
+
88
+ def authenticate(request, login, password)
89
+ return {:username => login, :auth_method => :login}
90
+ end
91
+
92
+ def login(request, params, cookies)
93
+ if params['broker_auth_key'] && params['broker_auth_iv']
94
+ return {:username => params['broker_auth_key'], :auth_method => :broker_auth}
95
+ else
96
+ data = JSON.parse(params['json_data'])
97
+ return {:username => data["rhlogin"], :auth_method => :login}
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,33 @@
1
+ module OpenShift
2
+ class DataStore
3
+ @oo_ds_provider = OpenShift::DataStore
4
+
5
+ def self.provider=(provider_class)
6
+ @oo_ds_provider = provider_class
7
+ end
8
+
9
+ def self.instance
10
+ @oo_ds_provider.new
11
+ end
12
+
13
+ def find(obj_type, user_id, id)
14
+ Rails.logger.debug "DataStore.find(#{obj_type}, #{user_id}, #{id})\n\n"
15
+ end
16
+
17
+ def find_all(obj_type, user_id=nil)
18
+ Rails.logger.debug "DataStore.find_all(#{obj_type}, #{user_id})\n\n"
19
+ end
20
+
21
+ def save(obj_type, user_id, id, obj)
22
+ Rails.logger.debug "DataStore.save(#{obj_type}, #{user_id}, #{id}, #{obj})\n\n"
23
+ end
24
+
25
+ def create(obj_type, user_id, id, obj)
26
+ Rails.logger.debug "DataStore.add(#{obj_type}, #{user_id}, #{id}, #{obj})\n\n"
27
+ end
28
+
29
+ def delete(obj_type, user_id, id)
30
+ Rails.logger.debug "DataStore.delete(#{obj_type}, #{user_id}, #{id})\n\n"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ module OpenShift
2
+ class DnsService
3
+ @oo_dns_provider = OpenShift::DnsService
4
+
5
+ def self.provider=(provider_class)
6
+ @oo_dns_provider = provider_class
7
+ end
8
+
9
+ def self.instance
10
+ @oo_dns_provider.new
11
+ end
12
+
13
+ def initialize
14
+ end
15
+
16
+ def namespace_available?(namespace)
17
+ return true
18
+ end
19
+
20
+ def register_namespace(namespace)
21
+ end
22
+
23
+ def deregister_namespace(namespace)
24
+ end
25
+
26
+ def register_application(app_name, namespace, public_hostname)
27
+ end
28
+
29
+ def deregister_application(app_name, namespace)
30
+ end
31
+
32
+ def modify_application(app_name, namespace, public_hostname)
33
+ end
34
+
35
+ def publish
36
+ end
37
+
38
+ def close
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,671 @@
1
+ require 'rubygems'
2
+ require 'mongo'
3
+ require 'pp'
4
+
5
+ module OpenShift
6
+ class MongoDataStore < OpenShift::DataStore
7
+ MAX_CON_RETRIES = 60
8
+ CON_RETRY_WAIT_TM = 0.5 # in secs
9
+
10
+ attr_reader :replica_set, :host_port, :user, :password, :db, :collections
11
+
12
+ def initialize(access_info = nil)
13
+ if access_info != nil
14
+ # no-op
15
+ elsif defined? Rails
16
+ access_info = Rails.application.config.datastore
17
+ else
18
+ raise Exception.new("Mongo DataStore service is not initialized")
19
+ end
20
+ @replica_set = access_info[:replica_set]
21
+ @host_port = access_info[:host_port]
22
+ @user = access_info[:user]
23
+ @password = access_info[:password]
24
+ @db = access_info[:db]
25
+ @collections = access_info[:collections]
26
+ end
27
+
28
+ def self.instance
29
+ OpenShift::MongoDataStore.new
30
+ end
31
+
32
+ def find(obj_type, user_id, id)
33
+ Rails.logger.debug "MongoDataStore.find(#{obj_type}, #{user_id}, #{id})\n\n"
34
+ case obj_type
35
+ when "CloudUser"
36
+ get_user(user_id)
37
+ when "Application"
38
+ get_app(user_id, id)
39
+ when "Domain"
40
+ get_domain(user_id, id)
41
+ when "ApplicationTemplate"
42
+ find_application_template(id)
43
+ end
44
+ end
45
+
46
+ def find_all(obj_type, user_id=nil, opts=nil, &block)
47
+ Rails.logger.debug "MongoDataStore.find_all(#{obj_type}, #{user_id}, #{opts})\n\n"
48
+ case obj_type
49
+ when "CloudUser"
50
+ get_users(opts, &block)
51
+ when "Application"
52
+ get_apps(user_id, &block)
53
+ when "Domain"
54
+ get_domains(user_id, &block)
55
+ when "ApplicationTemplate"
56
+ if opts.nil? || opts.empty?
57
+ find_all_application_templates(&block)
58
+ else
59
+ find_application_template_by_tag(opts[:tag], &block)
60
+ end
61
+ end
62
+ end
63
+
64
+ def find_all_logins(opts)
65
+ Rails.logger.debug "MongoDataStore.find_all_logins()\n\n"
66
+ query = {}
67
+ if opts
68
+ if opts[:with_gears]
69
+ query["apps.group_instances.gears.0"] = {"$exists" => true}
70
+ end
71
+ if opts[:with_usage]
72
+ query["usage_records.0"] = {"$exists" => true}
73
+ end
74
+ if opts[:with_plan]
75
+ query["$or"] = [{"pending_plan_id" => {"$ne" => nil}}, {"plan_id" => {"$ne" => nil}}]
76
+ end
77
+ end
78
+ mcursor = user_collection.find(query, {:fields => []})
79
+ ret = []
80
+ mcursor.each do |hash|
81
+ ret.push(hash['_id'])
82
+ end
83
+ ret
84
+ end
85
+
86
+ def find_by_gear_uuid(gear_uuid)
87
+ Rails.logger.debug "MongoDataStore.find_by_gear_uuid(#{gear_uuid})\n\n"
88
+ hash = find_one( user_collection, { "apps.group_instances.gears.uuid" => gear_uuid } )
89
+ return nil unless hash
90
+ user_hash_to_ret(hash)
91
+ end
92
+
93
+ def find_by_uuid(obj_type_of_uuid, uuid)
94
+ Rails.logger.debug "MongoDataStore.find_by_uuid(#{obj_type_of_uuid}, #{uuid})\n\n"
95
+ case obj_type_of_uuid
96
+ when "CloudUser"
97
+ get_user_by_uuid(uuid)
98
+ when "Application"
99
+ get_user_by_app_uuid(uuid)
100
+ when "Domain"
101
+ get_user_by_domain_uuid(uuid)
102
+ when "ApplicationTemplate"
103
+ find_application_template(uuid)
104
+ end
105
+ end
106
+
107
+ def find_subaccounts_by_parent_login(parent_id)
108
+ Rails.logger.debug "MongoDataStore.find_subaccounts_by_parent_login(#{parent_id})\n\n"
109
+ cur = MongoDataStore.rescue_con_failure { user_collection.find({ "parent_user_login" => parent_id }) }
110
+ return [] unless cur
111
+ hash_list = []
112
+ cur.each do |hash|
113
+ hash.delete("_id")
114
+ hash_list << hash
115
+ end
116
+
117
+ hash_list
118
+ end
119
+
120
+ def save(obj_type, user_id, id, obj_attrs)
121
+ Rails.logger.debug "MongoDataStore.save(#{obj_type}, #{user_id}, #{id}, #hidden)\n\n"
122
+ case obj_type
123
+ when "CloudUser"
124
+ put_user(user_id, obj_attrs)
125
+ when "Application"
126
+ put_app(user_id, id, obj_attrs)
127
+ when "Domain"
128
+ put_domain(user_id, id, obj_attrs)
129
+ when "UsageRecord"
130
+ put_usage_record(user_id, id, obj_attrs)
131
+ end
132
+ end
133
+
134
+ def create(obj_type, user_id, id, obj_attrs)
135
+ Rails.logger.debug "MongoDataStore.create(#{obj_type}, #{user_id}, #{id}, #hidden)\n\n"
136
+ case obj_type
137
+ when "CloudUser"
138
+ add_user(user_id, obj_attrs)
139
+ when "Application"
140
+ add_app(user_id, id, obj_attrs)
141
+ when "Domain"
142
+ add_domain(user_id, id, obj_attrs)
143
+ when "ApplicationTemplate"
144
+ save_application_template(id, obj_attrs)
145
+ end
146
+ end
147
+
148
+ def delete(obj_type, user_id, id=nil)
149
+ Rails.logger.debug "MongoDataStore.delete(#{obj_type}, #{user_id}, #{id})\n\n"
150
+ case obj_type
151
+ when "CloudUser"
152
+ delete_user(user_id)
153
+ when "Application"
154
+ delete_app(user_id, id)
155
+ when "Domain"
156
+ delete_domain(user_id, id)
157
+ when "ApplicationTemplate"
158
+ delete_application_template(id)
159
+ when "UsageRecord"
160
+ delete_usage_record(user_id, id)
161
+ end
162
+ end
163
+
164
+ def delete_usage_record_by_gear_uuid(user_id, gear_uuid, usage_type)
165
+ Rails.logger.debug "MongoDataStore.delete_usage_record_by_gear_uuid(#{user_id}, #{gear_uuid}, #{usage_type})\n\n"
166
+ update( user_collection, { "_id" => user_id },
167
+ { "$pull" => { "usage_records" => {"gear_uuid" => gear_uuid, "usage_type" => usage_type}}} )
168
+ end
169
+
170
+ def delete_usage_records_by_uuids(user_id, uuids)
171
+ Rails.logger.debug "MongoDataStore.delete_usage_record_by_gear_uuid(#{user_id}, #{uuids})\n\n"
172
+ update( user_collection, { "_id" => user_id },
173
+ { "$pull" => { "usage_records" => {"uuid" => {"$in" => uuids}} }} )
174
+ end
175
+
176
+ def db(connection_opts=nil)
177
+ if @replica_set
178
+ options = {:read => :secondary, :connect_timeout => 60}
179
+ options.merge!(connection_opts) if connection_opts
180
+ con = Mongo::ReplSetConnection.new(*@host_port << options)
181
+ else
182
+ con = Mongo::Connection.new(@host_port[0], @host_port[1])
183
+ end
184
+ user_db = con.db(@db)
185
+ user_db.authenticate(@user, @password)
186
+ user_db
187
+ end
188
+
189
+ def user_collection(connection_opts=nil)
190
+ db(connection_opts).collection(@collections[:user])
191
+ end
192
+
193
+ def find_one(collection, *args)
194
+ MongoDataStore.rescue_con_failure do
195
+ collection.find_one(*args)
196
+ end
197
+ end
198
+
199
+ def find_and_modify(collection, *args)
200
+ MongoDataStore.rescue_con_failure do
201
+ collection.find_and_modify(*args)
202
+ end
203
+ end
204
+
205
+ def insert(collection, *args)
206
+ MongoDataStore.rescue_con_failure do
207
+ collection.insert(*args)
208
+ end
209
+ end
210
+
211
+ def update(collection, *args)
212
+ MongoDataStore.rescue_con_failure do
213
+ collection.update(*args)
214
+ end
215
+ end
216
+
217
+ def remove(collection, *args)
218
+ MongoDataStore.rescue_con_failure do
219
+ collection.remove(*args)
220
+ end
221
+ end
222
+
223
+ # Ensure retry upon connection failure
224
+ def self.rescue_con_failure(max_retries=MAX_CON_RETRIES, retry_wait_tm=CON_RETRY_WAIT_TM)
225
+ retries = 0
226
+ begin
227
+ yield
228
+ rescue Mongo::ConnectionFailure => ex
229
+ retries += 1
230
+ raise ex if retries > max_retries
231
+ sleep(retry_wait_tm)
232
+ retry
233
+ end
234
+ end
235
+
236
+ def find_district(uuid, connection_opts=nil)
237
+ Rails.logger.debug "MongoDataStore.find_district(#{uuid})\n\n"
238
+ hash = find_one( district_collection(connection_opts), "_id" => uuid )
239
+ hash_to_district_ret(hash)
240
+ end
241
+
242
+ def find_district_by_name(name, connection_opts=nil)
243
+ Rails.logger.debug "MongoDataStore.find_district_by_name(#{name})\n\n"
244
+ hash = find_one( district_collection(connection_opts), "name" => name )
245
+ hash_to_district_ret(hash)
246
+ end
247
+
248
+ def find_all_districts()
249
+ Rails.logger.debug "find_all_districts()\n\n"
250
+ MongoDataStore.rescue_con_failure do
251
+ mcursor = district_collection.find()
252
+ cursor_to_district_hash(mcursor)
253
+ end
254
+ end
255
+
256
+ def find_district_with_node(server_identity)
257
+ Rails.logger.debug "find_district_with_node(#{server_identity})\n\n"
258
+ hash = find_one( district_collection, {"server_identities.name" => server_identity } )
259
+ hash_to_district_ret(hash)
260
+ end
261
+
262
+ def save_district(uuid, district_attrs)
263
+ Rails.logger.debug "save_district(#{uuid}, #{district_attrs.pretty_inspect})\n\n"
264
+ district_attrs["_id"] = uuid
265
+ orig_server_identities = district_attrs["server_identities"]
266
+ district_attrs_to_internal(district_attrs)
267
+ update( district_collection, { "_id" => uuid }, district_attrs, { :upsert => true } )
268
+ district_attrs.delete("_id")
269
+ district_attrs["server_identities"] = orig_server_identities
270
+ end
271
+
272
+ def delete_district(uuid)
273
+ Rails.logger.debug "delete_district(#{uuid})\n\n"
274
+ remove( district_collection, { "_id" => uuid, "active_server_identities_size" => 0 } )
275
+ end
276
+
277
+ def reserve_district_given_uid(uuid, uid)
278
+ Rails.logger.debug "reserve_district_given_uid(#{uuid}, #{uid})\n\n"
279
+ hash = find_and_modify( district_collection, {
280
+ :query => {"_id" => uuid, "available_capacity" => {"$gt" => 0}},
281
+ :update => {"$pull" => { "available_uids" => uid }, "$inc" => { "available_capacity" => -1 }},
282
+ :new => false })
283
+ return hash ? (hash["available_uids"].include? uid) : false
284
+ end
285
+
286
+ def reserve_district_uid(uuid)
287
+ Rails.logger.debug "reserve_district_uid(#{uuid})\n\n"
288
+ hash = find_and_modify( district_collection, {
289
+ :query => {"_id" => uuid, "available_capacity" => {"$gt" => 0}},
290
+ :update => {"$pop" => { "available_uids" => -1}, "$inc" => { "available_capacity" => -1 }},
291
+ :new => false })
292
+ return hash ? hash["available_uids"][0] : nil
293
+ end
294
+
295
+ def unreserve_district_uid(uuid, uid)
296
+ Rails.logger.debug "unreserve_district_uid(#{uuid})\n\n"
297
+ update( district_collection, {"_id" => uuid, "available_uids" => {"$ne" => uid}}, {"$push" => { "available_uids" => uid}, "$inc" => { "available_capacity" => 1 }} )
298
+ end
299
+
300
+ def add_district_node(uuid, server_identity)
301
+ Rails.logger.debug "add_district_node(#{uuid},#{server_identity})\n\n"
302
+ update( district_collection, {"_id" => uuid, "server_identities.name" => { "$ne" => server_identity }}, {"$push" => { "server_identities" => {"name" => server_identity, "active" => true}}, "$inc" => { "active_server_identities_size" => 1 }} )
303
+ end
304
+
305
+ def remove_district_node(uuid, server_identity)
306
+ Rails.logger.debug "remove_district_node(#{uuid},#{server_identity})\n\n"
307
+ hash = find_and_modify( district_collection, {
308
+ :query => { "_id" => uuid, "server_identities" => {"$elemMatch" => {"name" => server_identity, "active" => false}}},
309
+ :update => { "$pull" => { "server_identities" => {"name" => server_identity }}} })
310
+ return hash != nil
311
+ end
312
+
313
+ def deactivate_district_node(uuid, server_identity)
314
+ Rails.logger.debug "deactivate_district_node(#{uuid},#{server_identity})\n\n"
315
+ update( district_collection, {"_id" => uuid, "server_identities" => {"$elemMatch" => {"name" => server_identity, "active" => true}}}, {"$set" => { "server_identities.$.active" => false}, "$inc" => { "active_server_identities_size" => -1 }} )
316
+ end
317
+
318
+ def activate_district_node(uuid, server_identity)
319
+ Rails.logger.debug "activate_district_node(#{uuid},#{server_identity})\n\n"
320
+ update( district_collection, {"_id" => uuid, "server_identities" => {"$elemMatch" => {"name" => server_identity, "active" => false}}}, {"$set" => { "server_identities.$.active" => true}, "$inc" => { "active_server_identities_size" => 1 }} )
321
+ end
322
+
323
+ def add_district_uids(uuid, uids)
324
+ Rails.logger.debug "add_district_capacity(#{uuid},#{uids})\n\n"
325
+ update( district_collection, {"_id" => uuid}, {"$pushAll" => { "available_uids" => uids }, "$inc" => { "available_capacity" => uids.length, "max_uid" => uids.length, "max_capacity" => uids.length }} )
326
+ end
327
+
328
+ def remove_district_uids(uuid, uids)
329
+ Rails.logger.debug "remove_district_capacity(#{uuid},#{uids})\n\n"
330
+ update( district_collection, {"_id" => uuid, "available_uids" => uids[0]}, {"$pullAll" => { "available_uids" => uids }, "$inc" => { "available_capacity" => -uids.length, "max_uid" => -uids.length, "max_capacity" => -uids.length }} )
331
+ end
332
+
333
+ def inc_district_externally_reserved_uids_size(uuid)
334
+ Rails.logger.debug "inc_district_externally_reserved_uids_size(#{uuid})\n\n"
335
+ update( district_collection, {"_id" => uuid}, {"$inc" => { "externally_reserved_uids_size" => 1 }} )
336
+ end
337
+
338
+ def find_available_district(node_profile=nil)
339
+ node_profile = node_profile ? node_profile : "small"
340
+ MongoDataStore.rescue_con_failure do
341
+ hash = district_collection.find(
342
+ { "available_capacity" => { "$gt" => 0 },
343
+ "active_server_identities_size" => { "$gt" => 0 },
344
+ "node_profile" => node_profile}).sort(["available_capacity", "descending"]).limit(1).next
345
+ hash_to_district_ret(hash)
346
+ end
347
+ end
348
+
349
+ private
350
+
351
+ def find_application_template_by_tag(tag)
352
+ arr = application_template_collection.find( {"tags" => tag} )
353
+ return nil if arr.nil?
354
+ templates = []
355
+ arr.each do |hash|
356
+ hash.delete("_id")
357
+ templates.push(hash)
358
+ end
359
+ templates
360
+ end
361
+
362
+ def find_application_template(id)
363
+ hash = application_template_collection.find_one( {"_id" => id} )
364
+ return nil if hash.nil?
365
+ hash.delete("_id")
366
+ hash
367
+ end
368
+
369
+ def find_all_application_templates()
370
+ arr = application_template_collection.find()
371
+ return nil if arr.nil?
372
+ templates = []
373
+ arr.each do |hash|
374
+ hash.delete("_id")
375
+ templates.push(hash)
376
+ end
377
+ templates
378
+ end
379
+
380
+ def save_application_template(uuid, attrs)
381
+ Rails.logger.debug "MongoDataStore.save_application_template(#{uuid}, #{attrs.pretty_inspect})\n\n"
382
+ attrs["_id"] = uuid
383
+ application_template_collection.update({ "_id" => uuid }, attrs, { :upsert => true })
384
+ attrs.delete("_id")
385
+ end
386
+
387
+ def delete_application_template(uuid)
388
+ Rails.logger.debug "MongoDataStore.delete_application_template(#{uuid})\n\n"
389
+ application_template_collection.remove({ "_id" => uuid })
390
+ end
391
+
392
+ def application_template_collection
393
+ db.collection(@collections[:application_template])
394
+ end
395
+
396
+ def get_user(user_id)
397
+ hash = find_one( user_collection, "_id" => user_id )
398
+ return nil unless hash && !hash.empty?
399
+
400
+ user_hash_to_ret(hash)
401
+ end
402
+
403
+ def get_user_by_uuid(uuid)
404
+ hash = find_one( user_collection, "uuid" => uuid )
405
+ return nil unless hash && !hash.empty?
406
+
407
+ user_hash_to_ret(hash)
408
+ end
409
+
410
+ def get_user_by_app_uuid(uuid)
411
+ hash = find_one( user_collection, "apps.uuid" => uuid )
412
+ return nil unless hash && !hash.empty?
413
+
414
+ user_hash_to_ret(hash)
415
+ end
416
+
417
+ def get_user_by_domain_uuid(uuid)
418
+ hash = find_one( user_collection, "domains.uuid" => uuid )
419
+ return nil unless hash && !hash.empty?
420
+
421
+ user_hash_to_ret(hash)
422
+ end
423
+
424
+ def get_users(opts=nil)
425
+ MongoDataStore.rescue_con_failure do
426
+ query = {}
427
+ if opts
428
+ if opts[:with_gears]
429
+ query["apps.group_instances.gears.0"] = {"$exists" => true}
430
+ end
431
+ if opts[:with_usage]
432
+ query["usage_records.0"] = {"$exists" => true}
433
+ end
434
+ if opts[:with_plan]
435
+ query["$or"] = [{"pending_plan_id" => {"$ne" => nil}}, {"plan_id" => {"$ne" => nil}}]
436
+ end
437
+ end
438
+ mcursor = user_collection.find(query)
439
+ ret = []
440
+ mcursor.each do |hash|
441
+ if block_given?
442
+ yield user_hash_to_ret(hash)
443
+ else
444
+ ret.push(user_hash_to_ret(hash))
445
+ end
446
+ end
447
+ ret
448
+ end
449
+ end
450
+
451
+ def user_hash_to_ret(hash)
452
+ hash.delete("_id")
453
+ hash
454
+ end
455
+
456
+ def get_app(user_id, id)
457
+ hash = find_one( user_collection, { "_id" => user_id, "apps.name" => /^#{id}$/i }, :fields => ["apps"])
458
+ return nil unless hash && !hash.empty?
459
+
460
+ app_hash = nil
461
+ hash["apps"].each do |app|
462
+ if app["name"].downcase == id.downcase
463
+ app_hash = app
464
+ break
465
+ end
466
+ end if hash["apps"]
467
+ app_hash
468
+ end
469
+
470
+ def get_apps(user_id)
471
+ hash = find_one( user_collection, { "_id" => user_id }, :fields => ["apps"] )
472
+ return [] unless hash && !hash.empty?
473
+ return [] unless hash["apps"] && !hash["apps"].empty?
474
+ hash["apps"]
475
+ end
476
+
477
+ def get_domain(user_id, id)
478
+ hash = find_one( user_collection, { "_id" => user_id, "domains.uuid" => id }, :fields => ["domains"] )
479
+ return nil unless hash && !hash.empty?
480
+
481
+ domain_hash = nil
482
+ hash["domains"].each do |domain|
483
+ if domain["uuid"] == id
484
+ domain_hash = domain
485
+ break
486
+ end
487
+ end if hash["domains"]
488
+ domain_hash
489
+ end
490
+
491
+ def get_domains(user_id)
492
+ hash = find_one( user_collection, { "_id" => user_id }, :fields => ["domains"] )
493
+ return [] unless hash && !hash.empty?
494
+ return [] unless hash["domains"] && !hash["domains"].empty?
495
+ hash["domains"]
496
+ end
497
+
498
+
499
+ def put_user(user_id, changed_user_attrs)
500
+ changed_user_attrs.delete("apps")
501
+ changed_user_attrs.delete("domains")
502
+ changed_user_attrs.delete("consumed_gears")
503
+ changed_user_attrs.delete("usage_records")
504
+
505
+ update( user_collection, { "_id" => user_id }, { "$set" => changed_user_attrs } )
506
+ end
507
+
508
+ def add_user(user_id, user_attrs)
509
+ user_attrs["_id"] = user_id
510
+ user_attrs.delete("apps")
511
+ user_attrs.delete("domains")
512
+ insert(user_collection, user_attrs)
513
+ user_attrs.delete("_id")
514
+ end
515
+
516
+ def put_app(user_id, id, app_attrs)
517
+ app_attrs_to_internal(app_attrs)
518
+ ngears = app_attrs["ngears"]
519
+ ngears = ngears.to_i
520
+ app_attrs.delete("ngears")
521
+ usage_records = app_attrs["usage_records"]
522
+ app_attrs.delete("usage_records")
523
+ destroyed_gears = app_attrs["destroyed_gears"]
524
+ app_attrs.delete("destroyed_gears")
525
+
526
+ updates = { "$set" => { "apps.$" => app_attrs } }
527
+ if usage_records && !usage_records.empty?
528
+ updates["$pushAll"] = { "usage_records" => usage_records }
529
+ end
530
+ if ngears != 0
531
+ updates["$inc"] = { "consumed_gears" => ngears }
532
+ query = { "_id" => user_id, "apps.name" => id }
533
+ if ngears > 0
534
+ condition = "(this.consumed_gears + #{ngears}) <= this.max_gears"
535
+ query["$where"] = condition
536
+ end
537
+
538
+ if destroyed_gears && !destroyed_gears.empty?
539
+ query["apps.group_instances.gears.uuid"] = { "$all" => destroyed_gears }
540
+ end
541
+
542
+ hash = find_and_modify( user_collection, { :query => query,
543
+ :update => updates })
544
+ raise OpenShift::UserException.new("Consistency check failed. Could not update application '#{id}' for '#{user_id}'", 1) if hash == nil
545
+ else
546
+ update( user_collection, { "_id" => user_id, "apps.name" => id}, updates )
547
+ end
548
+ end
549
+
550
+ def add_app(user_id, id, app_attrs)
551
+ app_attrs_to_internal(app_attrs)
552
+ ngears = app_attrs["ngears"]
553
+ ngears = ngears.to_i
554
+ app_attrs.delete("ngears")
555
+ usage_records = app_attrs["usage_records"]
556
+ app_attrs.delete("usage_records")
557
+ app_attrs.delete("destroyed_gears")
558
+
559
+ updates = { "$push" => { "apps" => app_attrs }, "$inc" => { "consumed_gears" => ngears }}
560
+ if usage_records && !usage_records.empty?
561
+ updates["$pushAll"] = { "usage_records" => usage_records }
562
+ end
563
+
564
+ hash = find_and_modify( user_collection, { :query => { "_id" => user_id, "apps.name" => { "$ne" => id }, "domains" => {"$exists" => true},
565
+ "$where" => "((this.consumed_gears + #{ngears}) <= this.max_gears) && (this.domains.length > 0)"},
566
+ :update => updates })
567
+ raise OpenShift::UserException.new("Failed: Either application limit has already reached or " +
568
+ "domain doesn't exist for '#{user_id}'", 104) if hash == nil
569
+ end
570
+
571
+ def put_domain(user_id, id, domain_attrs)
572
+ #TODO: FIXME
573
+ # domain_updates = {}
574
+ # domain_attrs.each do |k, v|
575
+ # domain_updates["domains.$.#{k}"] = v
576
+ # domain_updates["apps.$.domain.#{k}"] = v
577
+ # end
578
+ # update( user_collection, { "_id" => user_id, "domains.uuid" => id}, { "$set" => domain_updates } )
579
+ update( user_collection, { "_id" => user_id, "domains.uuid" => id}, { "$set" => { "domains.$" => domain_attrs }} )
580
+ end
581
+
582
+ #TODO: Revisit the query once we support multiple domains per user
583
+ def add_domain(user_id, id, domain_attrs)
584
+ hash = find_and_modify( user_collection, { :query => { "_id" => user_id, "domains.uuid" => { "$ne" => id },
585
+ "$or" => [{"domains" => {"$exists" => true, "$size" => 0}}, {"domains" => {"$exists" => false}}]},
586
+ :update => { "$push" => { "domains" => domain_attrs } } })
587
+ raise OpenShift::UserException.new("Domain already exists for #{user_id}", 158) if hash == nil
588
+ end
589
+
590
+ def delete_user(user_id)
591
+ remove( user_collection, { "_id" => user_id, "$or" => [{"domains" => {"$exists" => true, "$size" => 0}},
592
+ {"domains" => {"$exists" => false}}], "$where" => "this.consumed_gears == 0"} )
593
+ end
594
+
595
+ def delete_app(user_id, id)
596
+ update( user_collection, { "_id" => user_id, "apps.name" => id},
597
+ { "$pull" => { "apps" => {"name" => id }}})
598
+ end
599
+
600
+ def put_usage_record(user_id, id, usage_attrs)
601
+ update( user_collection, { "_id" => user_id, "usage_records.uuid" => id}, { "$set" => { "usage_records.$" => usage_attrs }} )
602
+ end
603
+
604
+ def delete_usage_record(user_id, id)
605
+ update( user_collection, { "_id" => user_id, },
606
+ { "$pull" => { "usage_records" => {"uuid" => id }}} )
607
+ end
608
+
609
+ def app_attrs_to_internal(app_attrs)
610
+ app_attrs
611
+ end
612
+
613
+ def delete_domain(user_id, id)
614
+ hash = find_and_modify( user_collection, { :query => { "_id" => user_id, "domains.uuid" => id,
615
+ "$or" => [{"apps" => {"$exists" => true, "$size" => 0}},
616
+ {"apps" => {"$exists" => false}}] },
617
+ :update => { "$pull" => { "domains" => {"uuid" => id } } }})
618
+ raise OpenShift::UserException.new("Could not delete domain." +
619
+ "Domain has valid applications.", 128) if hash == nil
620
+ end
621
+
622
+ #district
623
+
624
+ def district_collection(connection_opts=nil)
625
+ db(connection_opts).collection(@collections[:district])
626
+ end
627
+
628
+ def cursor_to_district_hash(cursor)
629
+ return [] unless cursor
630
+
631
+ districts = []
632
+ cursor.each do |hash|
633
+ districts.push(hash_to_district_ret(hash))
634
+ end
635
+ districts
636
+ end
637
+
638
+ def hash_to_district_ret(hash)
639
+ return nil unless hash
640
+ hash.delete("_id")
641
+ if hash["server_identities"]
642
+ server_identities = {}
643
+ hash["server_identities"].each do |server_identity|
644
+ name = server_identity["name"]
645
+ server_identity.delete("name")
646
+ server_identities[name] = server_identity
647
+ end
648
+ hash["server_identities"] = server_identities
649
+ else
650
+ hash["server_identities"] = {}
651
+ end
652
+ hash
653
+ end
654
+
655
+ def district_attrs_to_internal(district_attrs)
656
+ if district_attrs
657
+ if district_attrs["server_identities"]
658
+ server_identities = []
659
+ district_attrs["server_identities"].each do |name, server_identity|
660
+ server_identity["name"] = name
661
+ server_identities.push(server_identity)
662
+ end
663
+ district_attrs["server_identities"] = server_identities
664
+ else
665
+ district_attrs["server_identities"] = []
666
+ end
667
+ end
668
+ district_attrs
669
+ end
670
+ end
671
+ end