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.
- data/COPYRIGHT +1 -0
- data/Gemfile +4 -0
- data/LICENSE +12 -0
- data/README.md +3 -0
- data/Rakefile +9 -0
- data/app/controllers/app_events_controller.rb +115 -0
- data/app/controllers/application_templates_controller.rb +19 -0
- data/app/controllers/applications_controller.rb +214 -0
- data/app/controllers/base_controller.rb +367 -0
- data/app/controllers/cartridges_controller.rb +48 -0
- data/app/controllers/descriptors_controller.rb +23 -0
- data/app/controllers/dns_resolvable_controller.rb +35 -0
- data/app/controllers/domains_controller.rb +156 -0
- data/app/controllers/emb_cart_controller.rb +276 -0
- data/app/controllers/emb_cart_events_controller.rb +52 -0
- data/app/controllers/environment_controller.rb +11 -0
- data/app/controllers/estimates_controller.rb +71 -0
- data/app/controllers/gear_groups_controller.rb +53 -0
- data/app/controllers/gears_controller.rb +70 -0
- data/app/controllers/keys_controller.rb +96 -0
- data/app/controllers/legacy_broker_controller.rb +510 -0
- data/app/controllers/quickstarts_controller.rb +29 -0
- data/app/controllers/user_controller.rb +38 -0
- data/app/helpers/cartridge_helper.rb +25 -0
- data/app/helpers/legacy_broker_helper.rb +21 -0
- data/app/helpers/user_action_logger.rb +38 -0
- data/app/models/application.rb +1718 -0
- data/app/models/application_template.rb +27 -0
- data/app/models/cartridge_cache.rb +51 -0
- data/app/models/cloud_user.rb +334 -0
- data/app/models/component_instance.rb +228 -0
- data/app/models/connection_endpoint.rb +10 -0
- data/app/models/district.rb +210 -0
- data/app/models/domain.rb +234 -0
- data/app/models/gear.rb +376 -0
- data/app/models/group_instance.rb +306 -0
- data/app/models/key.rb +20 -0
- data/app/models/legacy_reply.rb +15 -0
- data/app/models/legacy_request.rb +126 -0
- data/app/models/link.rb +11 -0
- data/app/models/message.rb +10 -0
- data/app/models/name_server_cache.rb +46 -0
- data/app/models/optional_param.rb +12 -0
- data/app/models/param.rb +13 -0
- data/app/models/remote_job.rb +57 -0
- data/app/models/rest_application.rb +126 -0
- data/app/models/rest_application10.rb +106 -0
- data/app/models/rest_application12.rb +124 -0
- data/app/models/rest_application_estimate.rb +12 -0
- data/app/models/rest_application_template.rb +20 -0
- data/app/models/rest_cartridge10.rb +41 -0
- data/app/models/rest_cartridge11.rb +151 -0
- data/app/models/rest_domain.rb +43 -0
- data/app/models/rest_domain10.rb +42 -0
- data/app/models/rest_estimates.rb +16 -0
- data/app/models/rest_gear.rb +14 -0
- data/app/models/rest_gear_group.rb +26 -0
- data/app/models/rest_key.rb +24 -0
- data/app/models/rest_reply.rb +31 -0
- data/app/models/rest_user.rb +43 -0
- data/app/models/result_io.rb +67 -0
- data/app/models/usage_record.rb +37 -0
- data/app/models/validators/app_validator.rb +30 -0
- data/app/models/validators/key_validator.rb +30 -0
- data/app/models/validators/namespace_validator.rb +18 -0
- data/config/routes.rb +36 -0
- data/lib/controller_engine.rb +7 -0
- data/lib/openshift-origin-controller.rb +14 -0
- data/lib/openshift/application_container_proxy.rb +241 -0
- data/lib/openshift/auth_service.rb +101 -0
- data/lib/openshift/data_store.rb +33 -0
- data/lib/openshift/dns_service.rb +41 -0
- data/lib/openshift/mongo_data_store.rb +671 -0
- data/openshift-origin-controller.gemspec +42 -0
- data/rubygem-openshift-origin-controller.spec +274 -0
- data/test/cucumber/application-estimate.feature +25 -0
- data/test/cucumber/cartridge-10gen-mms-agent.feature +28 -0
- data/test/cucumber/cartridge-cron.feature +32 -0
- data/test/cucumber/cartridge-haproxy.feature +31 -0
- data/test/cucumber/cartridge-jenkins-build.feature +12 -0
- data/test/cucumber/cartridge-jenkins-client.feature +10 -0
- data/test/cucumber/cartridge-lifecycle-diy.feature +21 -0
- data/test/cucumber/cartridge-lifecycle-jbossas.feature +61 -0
- data/test/cucumber/cartridge-lifecycle-jbosseap.feature +61 -0
- data/test/cucumber/cartridge-lifecycle-jbossews10.feature +61 -0
- data/test/cucumber/cartridge-lifecycle-jenkins.feature +41 -0
- data/test/cucumber/cartridge-lifecycle-nodejs.feature +59 -0
- data/test/cucumber/cartridge-lifecycle-perl.feature +40 -0
- data/test/cucumber/cartridge-lifecycle-php.feature +106 -0
- data/test/cucumber/cartridge-lifecycle-python.feature +40 -0
- data/test/cucumber/cartridge-lifecycle-ruby18.feature +49 -0
- data/test/cucumber/cartridge-lifecycle-ruby19.feature +41 -0
- data/test/cucumber/cartridge-mongodb.feature +31 -0
- data/test/cucumber/cartridge-mysql.feature +30 -0
- data/test/cucumber/cartridge-php.feature +14 -0
- data/test/cucumber/cartridge-phpmyadmin.feature +32 -0
- data/test/cucumber/cartridge-postgresql.feature +32 -0
- data/test/cucumber/cartridge-runtime-extended-db.feature +64 -0
- data/test/cucumber/cartridge-runtime-extended-jboss.feature +24 -0
- data/test/cucumber/cartridge-runtime-extended-nodejs.feature +21 -0
- data/test/cucumber/cartridge-runtime-extended-perl.feature +18 -0
- data/test/cucumber/cartridge-runtime-extended-php.feature +19 -0
- data/test/cucumber/cartridge-runtime-extended-python.feature +18 -0
- data/test/cucumber/cartridge-runtime-extended-ruby.feature +22 -0
- data/test/cucumber/cartridge-runtime-standard-diy.feature +6 -0
- data/test/cucumber/cartridge-runtime-standard-jbossas.feature +7 -0
- data/test/cucumber/cartridge-runtime-standard-jbosseap.feature +7 -0
- data/test/cucumber/cartridge-runtime-standard-jbossews10.feature +7 -0
- data/test/cucumber/cartridge-runtime-standard-jenkins.feature +8 -0
- data/test/cucumber/cartridge-runtime-standard-nodejs.feature +7 -0
- data/test/cucumber/cartridge-runtime-standard-perl.feature +6 -0
- data/test/cucumber/cartridge-runtime-standard-php.feature +6 -0
- data/test/cucumber/cartridge-runtime-standard-python.feature +6 -0
- data/test/cucumber/cartridge-runtime-standard-ruby.feature +19 -0
- data/test/cucumber/cartridge-switchyard.feature +36 -0
- data/test/cucumber/descriptor.feature +40 -0
- data/test/cucumber/embedded.feature +44 -0
- data/test/cucumber/idler.feature +75 -0
- data/test/cucumber/misc/descriptor/manifest.yml +22 -0
- data/test/cucumber/misc/php/db_test.php +21 -0
- data/test/cucumber/openshift-node.feature +21 -0
- data/test/cucumber/rest-application-templates.feature +31 -0
- data/test/cucumber/rest-applications.feature +431 -0
- data/test/cucumber/rest-cartridge-types.feature +16 -0
- data/test/cucumber/rest-domains.feature +276 -0
- data/test/cucumber/rest-gears.feature +38 -0
- data/test/cucumber/rest-keys.feature +247 -0
- data/test/cucumber/rest-quickstarts.feature +27 -0
- data/test/cucumber/rest-workflow.feature +64 -0
- data/test/cucumber/step_definitions/api_steps.rb +369 -0
- data/test/cucumber/step_definitions/application-estimate-steps.rb +51 -0
- data/test/cucumber/step_definitions/application_steps.rb +215 -0
- data/test/cucumber/step_definitions/cartridge-10gen-mms-agent_steps.rb +11 -0
- data/test/cucumber/step_definitions/cartridge-cron_steps.rb +51 -0
- data/test/cucumber/step_definitions/cartridge-haproxy_steps.rb +30 -0
- data/test/cucumber/step_definitions/cartridge-jenkins_steps.rb +93 -0
- data/test/cucumber/step_definitions/cartridge-lifecycle-nodejs_steps.rb +30 -0
- data/test/cucumber/step_definitions/cartridge-mongodb_steps.rb +60 -0
- data/test/cucumber/step_definitions/cartridge-mysql_steps.rb +56 -0
- data/test/cucumber/step_definitions/cartridge-php_steps.rb +72 -0
- data/test/cucumber/step_definitions/cartridge-postgresql_steps.rb +59 -0
- data/test/cucumber/step_definitions/cartridge-switchyard_steps.rb +29 -0
- data/test/cucumber/step_definitions/client_steps.rb +12 -0
- data/test/cucumber/step_definitions/descriptor_step.rb +32 -0
- data/test/cucumber/step_definitions/idler_steps.rb +37 -0
- data/test/cucumber/step_definitions/node_steps.rb +203 -0
- data/test/cucumber/step_definitions/runtime_steps.rb +547 -0
- data/test/cucumber/step_definitions/runtime_url_steps.rb +46 -0
- data/test/cucumber/step_definitions/trap-user-extended_steps.rb +14 -0
- data/test/cucumber/step_definitions/trap-user_steps.rb +58 -0
- data/test/cucumber/support/00_setup_helper.rb +106 -0
- data/test/cucumber/support/app_helper.rb +243 -0
- data/test/cucumber/support/assertions.rb +52 -0
- data/test/cucumber/support/command_helper.rb +453 -0
- data/test/cucumber/support/dns_helper.rb +54 -0
- data/test/cucumber/support/env.rb +5 -0
- data/test/cucumber/support/process_helper.rb +44 -0
- data/test/cucumber/support/runtime_support.rb +440 -0
- data/test/cucumber/support/unused.rb +27 -0
- data/test/cucumber/support/user_helper.rb +37 -0
- data/test/cucumber/trap-user-extended.feature +53 -0
- data/test/cucumber/trap-user.feature +34 -0
- data/test/ddns/1.168.192-rev.db.init +13 -0
- data/test/ddns/HOWTO.txt +207 -0
- data/test/ddns/Kexample.com.+157+06142.key +1 -0
- data/test/ddns/Kexample.com.+157+06142.private +7 -0
- data/test/ddns/authconfig.rb +14 -0
- data/test/ddns/example.com.db.init +23 -0
- data/test/ddns/example.com.key +4 -0
- data/test/ddns/named.ca +52 -0
- data/test/ddns/named.conf +48 -0
- data/test/ddns/named.empty +10 -0
- data/test/ddns/named.localhost +10 -0
- data/test/ddns/named.loopback +11 -0
- data/test/ddns/named.rfc1912.zones +42 -0
- data/test/ddns/named.root.key +5 -0
- data/test/ddns/named_service.rb +127 -0
- data/test/unit/bind_dns_service_test.rb +167 -0
- data/test/unit/broker_auth_test.rb +28 -0
- metadata +545 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'openshift-origin-controller'
|
|
3
|
+
require 'openshift-origin-dns-bind'
|
|
4
|
+
|
|
5
|
+
module DnsHelper
|
|
6
|
+
#
|
|
7
|
+
# Utility functions for checking namespace availability and removing dns entries
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
$dns_con = nil
|
|
11
|
+
|
|
12
|
+
def dns_service
|
|
13
|
+
if not $dns_con
|
|
14
|
+
$dns_con = OpenShift::BindPlugin.new({:server => "127.0.0.1",
|
|
15
|
+
:port => 53,
|
|
16
|
+
:keyname => "example.com",
|
|
17
|
+
:keyvalue => $bind_keyvalue,
|
|
18
|
+
:domain_suffix => $domain,
|
|
19
|
+
:zone => "example.com"})
|
|
20
|
+
end
|
|
21
|
+
$dns_con
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def namespace_available?(namespace)
|
|
25
|
+
return dns_service.namespace_available?(namespace)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Public: Removes DNS entries
|
|
29
|
+
#
|
|
30
|
+
# entries - The Array of entries to remove
|
|
31
|
+
#
|
|
32
|
+
# Examples
|
|
33
|
+
#
|
|
34
|
+
# remove_dns_entries(['myapp-test2.dev.rhcloud.com'])
|
|
35
|
+
# # => true
|
|
36
|
+
#
|
|
37
|
+
# Returns entries Array on success
|
|
38
|
+
def remove_dns_entries(entries=[])
|
|
39
|
+
if not entries.empty?
|
|
40
|
+
entries.each do |domain|
|
|
41
|
+
yes = dns_service.namespace_available?(domain)
|
|
42
|
+
if !yes
|
|
43
|
+
#puts "deregistering #{domain}"
|
|
44
|
+
dns_service.deregister_namespace(domain)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
dns_service.publish
|
|
49
|
+
dns_service.close
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
World(DnsHelper)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
module CommandHelper
|
|
4
|
+
def urls_from_files(pattern)
|
|
5
|
+
results = []
|
|
6
|
+
Dir.glob(pattern).each do |file|
|
|
7
|
+
File.new(file, "r").each {|line| results << line.chomp}
|
|
8
|
+
end
|
|
9
|
+
results
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_failure(url, pid=$$)
|
|
13
|
+
system("flock /tmp/rhc/lock echo '#{url}' >> #{$temp}/#{pid}-failures.log")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def failures
|
|
17
|
+
urls_from_files("#{$temp}/*-failures.log")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def add_success(url, pid=$$)
|
|
21
|
+
system("echo '#{url}' >> #{$temp}/#{pid}-success.log")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def successes(pattern="*")
|
|
25
|
+
urls_from_files("#{$temp}/#{pattern.to_s}-success.log")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def wait(pid, expected_urls, timeout=300)
|
|
29
|
+
begin
|
|
30
|
+
Timeout::timeout(timeout) do
|
|
31
|
+
Process.wait(pid)
|
|
32
|
+
exit_status = $?.exitstatus
|
|
33
|
+
$logger.error("Process #{pid} failed with #{exit_status}") if exit_status != 0
|
|
34
|
+
end
|
|
35
|
+
rescue Timeout::Error
|
|
36
|
+
$logger.error("Process #{pid} timed out")
|
|
37
|
+
# Log the remaining url's as failures
|
|
38
|
+
failed_urls = expected_urls - successes(pid)
|
|
39
|
+
$logger.error("Recording the following urls as failed = #{failed_urls.pretty_inspect}")
|
|
40
|
+
failed_urls.each {|url| add_failure(url, pid)}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
World(CommandHelper)
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# A small support API for runtime-centric test cases. It provides
|
|
2
|
+
# abstractions for an Account, Application, Gear, and Cartridge.
|
|
3
|
+
# The gear implementation is backed by ApplicationContainer from
|
|
4
|
+
# the openshift-origin-node package.
|
|
5
|
+
#
|
|
6
|
+
# Parts of this might be flimsy and not quite aligned with certain
|
|
7
|
+
# realities (especially with regards to scaling), but it should
|
|
8
|
+
# provide a decent starting point for the runtime tests and give
|
|
9
|
+
# us a single place to refactor.
|
|
10
|
+
|
|
11
|
+
require 'openshift-origin-node'
|
|
12
|
+
require 'openshift-origin-node/utils/shell_exec'
|
|
13
|
+
require 'etc'
|
|
14
|
+
require 'timeout'
|
|
15
|
+
|
|
16
|
+
# Some constants which might be misplaced here. Perhaps they should
|
|
17
|
+
# go in 00_setup_helper.rb?
|
|
18
|
+
$home_root ||= "/var/lib/openshift"
|
|
19
|
+
$libra_httpd_conf_d ||= "/etc/httpd/conf.d/openshift"
|
|
20
|
+
$cartridge_root ||= "/usr/libexec/openshift/cartridges"
|
|
21
|
+
$embedded_cartridge_root ||= "/usr/libexec/openshift/cartridges/embedded"
|
|
22
|
+
|
|
23
|
+
$app_registry = {}
|
|
24
|
+
|
|
25
|
+
module OpenShift
|
|
26
|
+
TIMEOUT = 120
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Represents a user account. A name and domain will be automatically
|
|
30
|
+
# generated upon init,
|
|
31
|
+
class TestAccount
|
|
32
|
+
attr_reader :name, :domain, :apps
|
|
33
|
+
|
|
34
|
+
def initialize(domain=nil)
|
|
35
|
+
@name, @domain = gen_unique_login_and_domain(domain)
|
|
36
|
+
@apps = Array.new
|
|
37
|
+
|
|
38
|
+
# shouldn't do stuff in the constructor, but we'll live
|
|
39
|
+
$logger.info("Created new account #{@name} with domain #{@domain}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Lifted from another test script.
|
|
43
|
+
def gen_unique_login_and_domain(domain=nil)
|
|
44
|
+
if !domain
|
|
45
|
+
chars = ("1".."9").to_a
|
|
46
|
+
domain = "ci" + Array.new(8, '').collect{chars[rand(chars.size)]}.join
|
|
47
|
+
end
|
|
48
|
+
login = "cucumber-test_#{domain}@example.com"
|
|
49
|
+
[ login, domain ]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Creates a new TestApplication instance associated with this account.
|
|
53
|
+
def create_app()
|
|
54
|
+
app = OpenShift::TestApplication.new(self)
|
|
55
|
+
|
|
56
|
+
$logger.info("Created new application #{app.name} for account #{@name}")
|
|
57
|
+
|
|
58
|
+
@apps << app
|
|
59
|
+
app
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Convenience function to get the first application for this account.
|
|
63
|
+
def default_app()
|
|
64
|
+
@apps[0]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Represents an application associated with an account. The name and
|
|
69
|
+
# UUID for the application is automatically generated upon init.
|
|
70
|
+
class TestApplication
|
|
71
|
+
attr_reader :name, :uuid, :account, :gears
|
|
72
|
+
attr_accessor :hot_deploy_enabled
|
|
73
|
+
|
|
74
|
+
def initialize(account)
|
|
75
|
+
@name = gen_unique_app_name
|
|
76
|
+
@uuid = gen_small_uuid
|
|
77
|
+
@account = account
|
|
78
|
+
@gears = Array.new
|
|
79
|
+
|
|
80
|
+
# abstracts the hot_deploy marker file as a first class
|
|
81
|
+
# property of the application
|
|
82
|
+
@hot_deploy_enabled = false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Lifted from another script.
|
|
86
|
+
def gen_unique_app_name
|
|
87
|
+
chars = ("1".."9").to_a
|
|
88
|
+
"app" + Array.new(4, '').collect{chars[rand(chars.size)]}.join
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Lifted from another script.
|
|
92
|
+
def gen_small_uuid
|
|
93
|
+
%x[/usr/bin/uuidgen].gsub('-', '').strip
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Creates a new empty gear associated with this application.
|
|
97
|
+
def create_gear
|
|
98
|
+
gear = OpenShift::TestGear.new(self)
|
|
99
|
+
gear.create
|
|
100
|
+
@gears << gear
|
|
101
|
+
gear
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Convenience function to get the first gear associated with
|
|
105
|
+
# this application.
|
|
106
|
+
def default_gear
|
|
107
|
+
@gears[0]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Tears down the application by calling destroy for each gear.
|
|
111
|
+
def destroy
|
|
112
|
+
$logger.info("Destroying application #{@name}")
|
|
113
|
+
@gears.each do |gear|
|
|
114
|
+
gear.destroy
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Collects and returns the PIDs for every cartridge associated
|
|
119
|
+
# with this application as determined by the PID file in the
|
|
120
|
+
# cartridge instance run directory. The result is a Hash:
|
|
121
|
+
#
|
|
122
|
+
# PID file basename => PID
|
|
123
|
+
#
|
|
124
|
+
# NOTE: This doesn't currently take into account the possibility
|
|
125
|
+
# of duplicate PID filenames across gears (in a scaled instance).
|
|
126
|
+
def current_cart_pids
|
|
127
|
+
pids = {}
|
|
128
|
+
|
|
129
|
+
@gears.each do |gear|
|
|
130
|
+
gear.carts.values.each do |cart|
|
|
131
|
+
Dir.glob("#{$home_root}/#{gear.uuid}/#{cart.name}/{run,pid}/*.pid") do |pid_file|
|
|
132
|
+
$logger.info("Reading pid file #{pid_file} for cart #{cart.name}")
|
|
133
|
+
pid = IO.read(pid_file).chomp
|
|
134
|
+
proc_name = File.basename(pid_file, ".pid")
|
|
135
|
+
|
|
136
|
+
pids[proc_name] = pid
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
pids
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Represents a gear associated with an application. The UUID for the gear
|
|
146
|
+
# is automatically generated on init.
|
|
147
|
+
#
|
|
148
|
+
# NOTE: Instantiating the TestGear is not enough for it to be used; make
|
|
149
|
+
# sure to call TestGear.create before performing cartridge operations.
|
|
150
|
+
class TestGear
|
|
151
|
+
include CommandHelper
|
|
152
|
+
|
|
153
|
+
attr_reader :uuid, :carts, :app, :container
|
|
154
|
+
|
|
155
|
+
def initialize(app)
|
|
156
|
+
@uuid = gen_small_uuid
|
|
157
|
+
@carts = Hash.new # cart name => cart
|
|
158
|
+
@app = app
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Lifted from another script.
|
|
162
|
+
def gen_small_uuid()
|
|
163
|
+
%x[/usr/bin/uuidgen].gsub('-', '').strip
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Creates the physical gear on a node by delegating work to the
|
|
167
|
+
# ApplicationContainer class. Be sure to call this before attempting
|
|
168
|
+
# cartridge operations.
|
|
169
|
+
def create()
|
|
170
|
+
$logger.info("Creating new gear #{@uuid} for application #{@app.name}")
|
|
171
|
+
|
|
172
|
+
outbuf = []
|
|
173
|
+
cmd = "oo-app-create -a #{@app.uuid} -c #{@uuid} --with-app-name #{@app.name} --with-namespace #{@app.account.domain}"
|
|
174
|
+
exit_code = runcon(cmd, $selinux_user, $selinux_role, $selinux_type, outbuf)
|
|
175
|
+
if exit_code != 0
|
|
176
|
+
$logger.error(outbuf)
|
|
177
|
+
raise Exception.new(outbuf)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Create the container object for use in the event listener later
|
|
181
|
+
@container = OpenShift::ApplicationContainer.new(@app.uuid, @uuid, nil, @app.name, @app.name, @app.account.domain, nil, nil)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Destroys the gear via ApplicationContainer
|
|
185
|
+
def destroy()
|
|
186
|
+
$logger.info("Destroying gear #{@uuid} of application #{@app.name}")
|
|
187
|
+
|
|
188
|
+
outbuf = []
|
|
189
|
+
cmd = "oo-app-destroy -a #{@app.uuid} -c #{@uuid} --with-namespace #{@app.account.domain} --with-app-name #{@app.name}"
|
|
190
|
+
exit_code = runcon(cmd, $selinux_user, $selinux_role, $selinux_type, outbuf)
|
|
191
|
+
if exit_code != 0
|
|
192
|
+
$logger.error(outbuf)
|
|
193
|
+
raise Exception.new(outbuf)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Adds an alias to the gear
|
|
198
|
+
def add_alias(alias_name)
|
|
199
|
+
$logger.info("Adding alias #{alias_name} to gear #{@uuid} of application #{@app.name}")
|
|
200
|
+
|
|
201
|
+
outbuf = []
|
|
202
|
+
cmd = "oo-add-alias --with-container-uuid #{@uuid} --with-container-name #{@app.name} --with-namespace #{@app.account.domain} --with-alias-name #{alias_name}"
|
|
203
|
+
exit_code = runcon(cmd, $selinux_user, $selinux_role, $selinux_type, outbuf)
|
|
204
|
+
if exit_code != 0
|
|
205
|
+
$logger.error(outbuf)
|
|
206
|
+
raise Exception.new(outbuf)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Removes an alias from the gear
|
|
211
|
+
# Adds an alias to the gear
|
|
212
|
+
def remove_alias(alias_name)
|
|
213
|
+
$logger.info("Adding alias #{alias_name} to gear #{@uuid} of application #{@app.name}")
|
|
214
|
+
|
|
215
|
+
outbuf = []
|
|
216
|
+
cmd = "oo-remove-alias --with-container-uuid #{@uuid} --with-container-name #{@app.name} --with-namespace #{@app.account.domain} --with-alias-name #{alias_name}"
|
|
217
|
+
exit_code = runcon(cmd, $selinux_user, $selinux_role, $selinux_type, outbuf)
|
|
218
|
+
if exit_code != 0
|
|
219
|
+
$logger.error(outbuf)
|
|
220
|
+
raise Exception.new(outbuf)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Creates a new TestCartridge and associates it with this gear.
|
|
225
|
+
#
|
|
226
|
+
# NOTE: The cartridge is instantiated, but no hooks (such as
|
|
227
|
+
# configure) are executed.
|
|
228
|
+
def add_cartridge(cart_name, type = TestCartridge::Standard)
|
|
229
|
+
cart = OpenShift::TestCartridge.new(cart_name, self, type)
|
|
230
|
+
@carts[cart.name] = cart
|
|
231
|
+
cart
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Convenience function to retrieve the first cartridge for the gear.
|
|
235
|
+
def default_cart()
|
|
236
|
+
@carts.values[0]
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Represents a cartridge associated with a gear. Supports firing events
|
|
241
|
+
# and listener registration for cartridge-specific concerns.
|
|
242
|
+
class TestCartridge
|
|
243
|
+
include CommandHelper
|
|
244
|
+
|
|
245
|
+
attr_reader :name, :gear, :path, :type, :metadata
|
|
246
|
+
|
|
247
|
+
# We need to differentiate between non/embedded carts, as they have
|
|
248
|
+
# different root paths on the node filesystem.
|
|
249
|
+
Standard = 0
|
|
250
|
+
Embedded = 1
|
|
251
|
+
|
|
252
|
+
def initialize(name, gear, type = Standard)
|
|
253
|
+
@name = name
|
|
254
|
+
@gear = gear
|
|
255
|
+
@type = type
|
|
256
|
+
|
|
257
|
+
@metadata = {} # a place for cart specific helpers to put stuff
|
|
258
|
+
|
|
259
|
+
local_root = (@type == Standard) ? $cartridge_root : $embedded_cartridge_root
|
|
260
|
+
|
|
261
|
+
@cart_path = "#{local_root}/#{@name}"
|
|
262
|
+
@hooks_path = "#{@cart_path}/info/hooks"
|
|
263
|
+
|
|
264
|
+
# Add new listener classes here for now
|
|
265
|
+
@listeners = [ OpenShift::TestCartridgeListeners::ConfigureCartListener.new,
|
|
266
|
+
OpenShift::TestCartridgeListeners::DatabaseCartListener.new
|
|
267
|
+
]
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Convenience wrapper to invoke the configure hook.
|
|
271
|
+
def configure()
|
|
272
|
+
run_hook "configure"
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Convenience wrapper to invoke the deconfigure hook.
|
|
276
|
+
def deconfigure()
|
|
277
|
+
run_hook "deconfigure"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Convenience wrapper to invoke the start hook.
|
|
281
|
+
def start()
|
|
282
|
+
run_hook "start"
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Convenience wrapper to invoke the stop hook.
|
|
286
|
+
def stop()
|
|
287
|
+
run_hook "stop"
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Convenience wrapper to invoke the status hook.
|
|
291
|
+
def status()
|
|
292
|
+
run_hook "status"
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Invokes an arbitrary hook on the cartridge, passing through
|
|
296
|
+
# any extra arguments specified by extra_args (if present). An
|
|
297
|
+
# exception will be raised if the exit code of the hook does
|
|
298
|
+
# not match expected_exitcode (which is 0 by default). The
|
|
299
|
+
# hook is executed in the selinux context of the user and role
|
|
300
|
+
# defined in the global constants provided in 00_setup_helper.
|
|
301
|
+
def run_hook(hook, expected_exitcode=0, extra_args=[])
|
|
302
|
+
exitcode, output = run_hook_output(hook, expected_exitcode, extra_args)
|
|
303
|
+
exitcode
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def run_hook_output(hook, expected_exitcode=0, extra_args=[])
|
|
307
|
+
$logger.info("Running #{hook} hook for cartridge #{@name} in gear #{@gear.uuid} for application #{@gear.app.name}")
|
|
308
|
+
|
|
309
|
+
cmd = %Q{#{@hooks_path}/#{hook} '#{@gear.app.name}' '#{@gear.app.account.domain}' #{@gear.uuid} #{extra_args.join(" ")}}
|
|
310
|
+
|
|
311
|
+
output = Array.new
|
|
312
|
+
exitcode = runcon cmd, $selinux_user, $selinux_role, $selinux_type, output, TIMEOUT
|
|
313
|
+
|
|
314
|
+
# Sanitize the command output. For now, the only major problem we're aware
|
|
315
|
+
# of is colorized output containing escape characters. The sanitization should
|
|
316
|
+
# really be taken care of in downstream formatters, but we have no control over
|
|
317
|
+
# those at present.
|
|
318
|
+
output = output.collect {|s| s.gsub(/\e\[(\d+)m/, '')}
|
|
319
|
+
|
|
320
|
+
raise %Q{Error (#{exitcode}) running #{cmd}: #{output.join("\n")}} unless exitcode == expected_exitcode
|
|
321
|
+
|
|
322
|
+
notify_listeners "#{hook}_hook_completed", { :cart => self, :exitcode => exitcode, :output => output}
|
|
323
|
+
|
|
324
|
+
[exitcode, output]
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Notify cart listeners of an event
|
|
328
|
+
def notify_listeners(event, args={})
|
|
329
|
+
@listeners.each do |listener|
|
|
330
|
+
if listener.respond_to?(event) && listener.supports?(@name)
|
|
331
|
+
$logger.info("Notifying #{listener.class.name} of #{event} event")
|
|
332
|
+
listener.send(event, args)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Cartridge listeners are intended to be invoked by TestCartridge instances
|
|
339
|
+
# at various points in their lifecycle, such as post-hook. The listeners
|
|
340
|
+
# are given an opportunity to respond to the results of cartridge actions
|
|
341
|
+
# and attach supplementary information to the cartridge instance which
|
|
342
|
+
# can be used to provide steps with cartridge specific context.
|
|
343
|
+
#
|
|
344
|
+
# Currently supported event patterns a listener may receive:
|
|
345
|
+
#
|
|
346
|
+
# {hook_name}_hook_completed(cart, exitcode, output)
|
|
347
|
+
# - invoked after a successful hook execution in the cartridge
|
|
348
|
+
module TestCartridgeListeners
|
|
349
|
+
|
|
350
|
+
# Pretend we're the broker's application model
|
|
351
|
+
class ConfigureCartListener
|
|
352
|
+
# We need to process all configure output for all cartridges
|
|
353
|
+
def supports?(cart_name)
|
|
354
|
+
true
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def configure_hook_completed(args)
|
|
358
|
+
if args.key?(:output) && ! args[:output].empty?
|
|
359
|
+
homedir = args[:cart].gear.container.user.homedir
|
|
360
|
+
|
|
361
|
+
args[:output].first.split(/\n/).each { |line|
|
|
362
|
+
case line
|
|
363
|
+
when /^ENV_VAR_ADD: .*/
|
|
364
|
+
key, value = line['ENV_VAR_ADD: '.length..-1].chomp.split('=')
|
|
365
|
+
File.open(File.join(homedir, '.env', key),
|
|
366
|
+
File::WRONLY|File::TRUNC|File::CREAT) do |file|
|
|
367
|
+
file.write "export #{key}='#{value}'"
|
|
368
|
+
end
|
|
369
|
+
when /^ENV_VAR_REMOVE: .*/
|
|
370
|
+
key = line['ENV_VAR_REMOVE: '.length..-1].chomp
|
|
371
|
+
FileUtils.rm_f File.join(homedir, '.env', key)
|
|
372
|
+
end
|
|
373
|
+
}
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
class DatabaseCartListener
|
|
379
|
+
def supports?(cart_name)
|
|
380
|
+
['mysql-5.1', 'mongodb-2.2', 'postgresql-8.4'].include?(cart_name)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
class DbConnection
|
|
384
|
+
attr_accessor :username, :password, :ip, :port
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Processes the output of the cartridge configure script and scrapes
|
|
388
|
+
# it for connectivity details (such as IP and credentials).
|
|
389
|
+
#
|
|
390
|
+
# Adds a new attribute 'db' of type DbConnection to the cart with the
|
|
391
|
+
# scraped details.
|
|
392
|
+
def configure_hook_completed(args)
|
|
393
|
+
$logger.info("DatabaseCartListener is processing configure hook results")
|
|
394
|
+
|
|
395
|
+
cart = args[:cart]
|
|
396
|
+
output = args[:output]
|
|
397
|
+
|
|
398
|
+
my_username_pattern = /Root User: (\S+)/
|
|
399
|
+
my_password_pattern = /Root Password: (\S+)/
|
|
400
|
+
|
|
401
|
+
# make this smarter if there are more use cases
|
|
402
|
+
ip_pattern_prefix = cart.name[/[^-]*/]
|
|
403
|
+
my_ip_pattern = /#{ip_pattern_prefix}:\/\/(\d+\.\d+\.\d+\.\d+):(\d+)/
|
|
404
|
+
|
|
405
|
+
db = DbConnection.new
|
|
406
|
+
|
|
407
|
+
output.each do |line|
|
|
408
|
+
if line.match(my_username_pattern)
|
|
409
|
+
db.username = $1
|
|
410
|
+
end
|
|
411
|
+
if line.match(my_password_pattern)
|
|
412
|
+
db.password = $1
|
|
413
|
+
end
|
|
414
|
+
if line.match(my_ip_pattern)
|
|
415
|
+
db.ip = $1
|
|
416
|
+
db.port = $2
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
$logger.info("DatabaseCartListener is adding a DbConnection to cartridge #{cart.name}: #{db.inspect}")
|
|
421
|
+
cart.instance_variable_set(:@db, db)
|
|
422
|
+
cart.instance_eval('def db; @db; end')
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
#
|
|
428
|
+
# Only raise timeout exceptions...
|
|
429
|
+
def self.timeout(seconds, dflt = nil)
|
|
430
|
+
begin
|
|
431
|
+
Timeout::timeout(seconds) do
|
|
432
|
+
yield
|
|
433
|
+
end
|
|
434
|
+
rescue Timeout::Error
|
|
435
|
+
raise if dflt.instance_of? Timeout::Error
|
|
436
|
+
dflt
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|