forj 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +59 -0
- data/Gemfile +14 -15
- data/Rakefile +11 -3
- data/bin/forj +231 -338
- data/forj.gemspec +4 -7
- data/forj/defaults.yaml +3 -3
- data/lib/appinit.rb +21 -32
- data/lib/boot.rb +156 -0
- data/lib/cloud_connection.rb +42 -0
- data/lib/cloud_test.rb +86 -68
- data/lib/destroy.rb +97 -0
- data/lib/forj-settings.rb +350 -167
- data/lib/forj/ForjCli.rb +12 -14
- data/lib/forj/ForjCore.rb +78 -85
- data/lib/forj/process/ForjProcess.rb +1157 -771
- data/lib/get.rb +51 -0
- data/lib/ssh.rb +86 -78
- data/spec/boot_spec.rb +0 -1
- data/spec/spec_helper.rb +65 -65
- metadata +14 -22
data/lib/forj/ForjCli.rb
CHANGED
@@ -20,20 +20,18 @@
|
|
20
20
|
|
21
21
|
# Define framework object on BaseDefinition
|
22
22
|
# See lib/core/definition.rb for function details usage.
|
23
|
-
|
24
|
-
|
25
23
|
class Lorj::BaseDefinition
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
24
|
+
# ************************************ SSH Object
|
25
|
+
define_obj(:ssh,
|
26
|
+
|
27
|
+
:create_e => :ssh_connection
|
28
|
+
)
|
29
|
+
obj_needs :CloudObject, :forge
|
30
|
+
obj_needs :data, :instance_name
|
31
|
+
obj_needs :data, :keypair_name
|
32
|
+
obj_needs :data, :keypair_path
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
obj_needs_optional
|
35
|
+
obj_needs :data, :forge_server
|
36
|
+
obj_needs :data, :ssh_user
|
39
37
|
end
|
data/lib/forj/ForjCore.rb
CHANGED
@@ -15,99 +15,92 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
FORJCORE_PATH = File.expand_path(File.dirname(__FILE__))
|
19
|
+
|
20
|
+
require File.join(FORJCORE_PATH, 'process', 'ForjProcess.rb')
|
21
|
+
|
18
22
|
# Defines how to manage Maestro and forges
|
19
23
|
# create a maestro box. Identify a forge instance, delete it,...
|
20
24
|
|
21
25
|
# Define framework object on BaseDefinition
|
22
26
|
# See lib/core/definition.rb for function details usage.
|
27
|
+
class Lorj::BaseDefinition
|
28
|
+
process_default :use_controller => false
|
23
29
|
|
24
|
-
|
30
|
+
# ******************* Maestro Repository object
|
31
|
+
define_obj :maestro_repository,
|
25
32
|
|
26
|
-
|
33
|
+
:create_e => :clone_or_use_maestro_repo
|
27
34
|
|
28
|
-
|
35
|
+
obj_needs :data, :maestro_url
|
36
|
+
|
37
|
+
obj_needs_optional
|
38
|
+
obj_needs :data, :maestro_repo
|
39
|
+
|
40
|
+
# ******************* Infra Repository object
|
41
|
+
define_obj :infra_repository,
|
42
|
+
|
43
|
+
:create_e => :create_or_use_infra
|
44
|
+
|
45
|
+
obj_needs :CloudObject, :maestro_repository
|
46
|
+
obj_needs :data, :infra_repo
|
47
|
+
obj_needs :data, :branch
|
48
|
+
|
49
|
+
# ******************* metadata object
|
50
|
+
define_obj :metadata,
|
51
|
+
|
52
|
+
:create_e => :build_metadata
|
53
|
+
|
54
|
+
obj_needs :data, :instance_name
|
55
|
+
obj_needs :data, :network_name
|
56
|
+
obj_needs :data, :security_group
|
57
|
+
obj_needs :data, :keypair_name
|
58
|
+
obj_needs :data, :image_name
|
59
|
+
obj_needs :data, :bp_flavor
|
60
|
+
obj_needs :data, :compute
|
61
|
+
obj_needs :data, :branch
|
62
|
+
obj_needs :data, :domain_name
|
63
|
+
obj_needs :data, :tenant_name
|
64
|
+
# sent in base64
|
65
|
+
obj_needs :data, :os_user
|
66
|
+
obj_needs :data, :os_enckey
|
67
|
+
obj_needs :data, :account_id
|
68
|
+
obj_needs :data, :account_key
|
69
|
+
obj_needs_optional
|
70
|
+
|
71
|
+
# If requested by user, ask Maestro to manage the DNS.
|
72
|
+
obj_needs :data, :dns_service
|
73
|
+
obj_needs :data, :dns_tenant_id
|
74
|
+
|
75
|
+
# If requested by user, ask Maestro to instantiate a blueprint.
|
76
|
+
obj_needs :data, :blueprint
|
77
|
+
# Add init bootstrap additional steps
|
78
|
+
obj_needs :data, :bootstrap
|
79
|
+
# Add init additional git clone steps.
|
80
|
+
obj_needs :data, :repos
|
81
|
+
|
82
|
+
# ******************* userdata object
|
83
|
+
define_obj :userdata,
|
84
|
+
|
85
|
+
:create_e => :build_userdata
|
86
|
+
|
87
|
+
obj_needs :CloudObject, :maestro_repository
|
88
|
+
obj_needs :CloudObject, :metadata
|
89
|
+
obj_needs :CloudObject, :infra_repository
|
90
|
+
|
91
|
+
# ******************* forge object
|
92
|
+
define_obj :forge,
|
93
|
+
|
94
|
+
:create_e => :build_forge,
|
95
|
+
:delete_e => :delete_forge,
|
96
|
+
:get_e => :get_forge
|
29
97
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
{
|
35
|
-
:create_e => :clone_or_use_maestro_repo
|
36
|
-
}
|
37
|
-
|
38
|
-
obj_needs :data, :maestro_url
|
39
|
-
|
40
|
-
obj_needs_optional
|
41
|
-
obj_needs :data, :maestro_repo
|
42
|
-
|
43
|
-
# ******************* Infra Repository object
|
44
|
-
define_obj :infra_repository,
|
45
|
-
{
|
46
|
-
:create_e => :create_or_use_infra
|
47
|
-
}
|
48
|
-
|
49
|
-
obj_needs :CloudObject, :maestro_repository
|
50
|
-
obj_needs :data, :infra_repo
|
51
|
-
obj_needs :data, :branch
|
52
|
-
|
53
|
-
# ******************* metadata object
|
54
|
-
define_obj :metadata,
|
55
|
-
{
|
56
|
-
:create_e => :build_metadata
|
57
|
-
}
|
58
|
-
|
59
|
-
obj_needs :data, :instance_name
|
60
|
-
obj_needs :data, :network_name
|
61
|
-
obj_needs :data, :security_group
|
62
|
-
obj_needs :data, :keypair_name
|
63
|
-
obj_needs :data, :image_name
|
64
|
-
obj_needs :data, :bp_flavor
|
65
|
-
obj_needs :data, :compute
|
66
|
-
obj_needs :data, :branch
|
67
|
-
obj_needs :data, :domain_name
|
68
|
-
obj_needs :data, :tenant_name
|
69
|
-
# sent in base64
|
70
|
-
obj_needs :data, :os_user
|
71
|
-
obj_needs :data, :os_enckey
|
72
|
-
obj_needs :data, :account_id
|
73
|
-
obj_needs :data, :account_key
|
74
|
-
obj_needs_optional
|
75
|
-
|
76
|
-
# If requested by user, ask Maestro to manage the DNS.
|
77
|
-
obj_needs :data, :dns_service
|
78
|
-
obj_needs :data, :dns_tenant_id
|
79
|
-
|
80
|
-
# If requested by user, ask Maestro to instantiate a blueprint.
|
81
|
-
obj_needs :data, :blueprint
|
82
|
-
# Add init bootstrap additional steps
|
83
|
-
obj_needs :data, :bootstrap
|
84
|
-
# Add init additional git clone steps.
|
85
|
-
obj_needs :data, :repos
|
86
|
-
|
87
|
-
# ******************* userdata object
|
88
|
-
define_obj :userdata,
|
89
|
-
{
|
90
|
-
:create_e => :build_userdata
|
91
|
-
}
|
92
|
-
|
93
|
-
obj_needs :CloudObject, :maestro_repository
|
94
|
-
obj_needs :CloudObject, :metadata
|
95
|
-
obj_needs :CloudObject, :infra_repository
|
96
|
-
|
97
|
-
# ******************* forge object
|
98
|
-
define_obj :forge,
|
99
|
-
{
|
100
|
-
:create_e => :build_forge,
|
101
|
-
:delete_e => :delete_forge,
|
102
|
-
:get_e => :get_forge
|
103
|
-
}
|
104
|
-
obj_needs :CloudObject, :compute_connection
|
105
|
-
obj_needs :CloudObject, :metadata, { :for => [:create_e] }
|
106
|
-
obj_needs :CloudObject, :userdata, { :for => [:create_e] }
|
107
|
-
obj_needs :data, :instance_name, { :for => [:create_e] }
|
108
|
-
|
109
|
-
obj_needs_optional
|
110
|
-
obj_needs :CloudObject, :server
|
111
|
-
obj_needs :data, :blueprint
|
98
|
+
obj_needs :CloudObject, :compute_connection
|
99
|
+
obj_needs :CloudObject, :metadata, :for => [:create_e]
|
100
|
+
obj_needs :CloudObject, :userdata, :for => [:create_e]
|
101
|
+
obj_needs :data, :instance_name, :for => [:create_e]
|
112
102
|
|
103
|
+
obj_needs_optional
|
104
|
+
obj_needs :CloudObject, :server
|
105
|
+
obj_needs :data, :blueprint
|
113
106
|
end
|
@@ -26,882 +26,1268 @@ require 'encryptor' # gem install encryptor
|
|
26
26
|
require 'base64'
|
27
27
|
require 'net/ssh'
|
28
28
|
|
29
|
-
|
29
|
+
INFRA_VERSION = '0.0.37'
|
30
30
|
|
31
|
-
# Functions for boot
|
31
|
+
# Functions for boot - build_forge
|
32
32
|
class ForjCoreProcess
|
33
|
+
def build_forge(sObjectType, hParams)
|
34
|
+
forge_exist?(sObjectType)
|
33
35
|
|
34
|
-
|
35
|
-
key_file = File.join($FORJ_CREDS_PATH, '.key')
|
36
|
-
|
37
|
-
if not File.exists?(key_file)
|
38
|
-
# Need to create a random key.
|
39
|
-
entr = {
|
40
|
-
:key => rand(36**10).to_s(36),
|
41
|
-
:salt => Time.now.to_i.to_s,
|
42
|
-
:iv => Base64::strict_encode64(OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv)
|
43
|
-
}
|
44
|
-
|
45
|
-
PrcLib.debug("Writing '%s' key file" % key_file)
|
46
|
-
File.open(key_file, 'w') do |out|
|
47
|
-
out.write(Base64::encode64(entr.to_yaml))
|
48
|
-
end
|
49
|
-
else
|
50
|
-
PrcLib.debug("Loading '%s' key file" % key_file)
|
51
|
-
encoded_key = IO.read(key_file)
|
52
|
-
entr = YAML.load(Base64::decode64(encoded_key))
|
53
|
-
end
|
54
|
-
os_enckey = hParams[:os_enckey]
|
36
|
+
o_server = data_objects(:server, :ObjectData)
|
55
37
|
|
56
|
-
|
57
|
-
os_key = Encryptor.decrypt(
|
58
|
-
:value => Base64::strict_decode64(os_enckey),
|
59
|
-
:key => entr[:key],
|
60
|
-
:iv => Base64::strict_decode64(entr[:iv]),
|
61
|
-
:salt => entr[:salt]
|
62
|
-
)
|
63
|
-
rescue => e
|
64
|
-
raise "Unable to decript your password. You need to re-execute setup."
|
65
|
-
end
|
38
|
+
boot_options = boot_keypairs(o_server)
|
66
39
|
|
67
|
-
|
68
|
-
|
69
|
-
pipe.puts('HPCLOUD_OS_USER=%s' % [hParams[:os_user]] )
|
70
|
-
pipe.puts('HPCLOUD_OS_KEY=%s' % [os_key] )
|
71
|
-
pipe.puts('DNS_KEY=%s' % [hParams[:account_id]] )
|
72
|
-
pipe.puts('DNS_SECRET=%s' % [hParams[:account_key]])
|
73
|
-
pipe.close_write
|
74
|
-
hpcloud_priv = pipe.read
|
75
|
-
}
|
40
|
+
# Define the log lines to get and test.
|
41
|
+
config.set(:log_lines, 5)
|
76
42
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
'cdksite' => config.get(:server_name),
|
81
|
-
'cdkdomain' => hParams[:domain_name],
|
82
|
-
'eroip' => '127.0.0.1',
|
83
|
-
'erosite' => config.get(:server_name),
|
84
|
-
'erodomain' => hParams[:domain_name],
|
85
|
-
'gitbranch' => hParams[:branch],
|
86
|
-
'security_groups' => hParams[:security_group],
|
87
|
-
'tenant_name' => hParams[:tenant_name],
|
88
|
-
'network_name' => hParams[:network_name],
|
89
|
-
'hpcloud_os_region' => hParams[:compute],
|
90
|
-
'PUPPET_DEBUG' => 'True',
|
91
|
-
'image_name' => hParams[:image_name],
|
92
|
-
'key_name' => hParams[:keypair_name],
|
93
|
-
'hpcloud_priv' => Base64.strict_encode64(hpcloud_priv).gsub('=', '') # Remove pad
|
94
|
-
}
|
43
|
+
PrcLib.info("Maestro server '%s' id is '%s'.",
|
44
|
+
o_server[:name], o_server[:id])
|
45
|
+
# Waiting for server to come online before assigning a public IP.
|
95
46
|
|
96
|
-
|
97
|
-
|
98
|
-
hMeta['dns_tenantid'] = hParams[:dns_tenant_id]
|
99
|
-
end
|
100
|
-
# If requested by user, ask Maestro to instantiate a blueprint.
|
101
|
-
hMeta['blueprint'] = hParams[:blueprint] if hParams[:blueprint]
|
47
|
+
s_status = :checking
|
48
|
+
maestro_create_status(s_status)
|
102
49
|
|
103
|
-
|
104
|
-
hMeta['repos'] = hParams[:repos] if hParams[:repos]
|
105
|
-
# Add init bootstrap additionnal steps
|
106
|
-
hMeta['bootstrap'] = hParams[:bootstrap] if hParams[:bootstrap]
|
50
|
+
o_address = data_objects(:public_ip, :ObjectData)
|
107
51
|
|
108
|
-
|
52
|
+
s_status = active_server?(o_server, o_address, boot_options[:keys],
|
53
|
+
boot_options[:coherent], s_status
|
54
|
+
)
|
109
55
|
|
110
|
-
|
111
|
-
hMetaPrintable['hpcloud_priv'] = "XXX - data hidden - XXX"
|
112
|
-
PrcLib.info("Metadata set:\n%s" % hMetaPrintable)
|
56
|
+
till_server_active(s_status, o_server, o_address, boot_options)
|
113
57
|
|
114
|
-
|
115
|
-
oMetaData[:meta_data] = hMeta
|
58
|
+
o_forge = get_forge(sObjectType, config[:instance_name], hParams)
|
116
59
|
|
117
|
-
|
118
|
-
|
60
|
+
read_blueprint_implemented(o_forge, o_address)
|
61
|
+
o_forge
|
62
|
+
end
|
119
63
|
|
120
|
-
|
64
|
+
def forge_exist?(sObjectType)
|
65
|
+
o_forge = process_get(sObjectType, config[:instance_name])
|
66
|
+
if o_forge.empty? || o_forge[:servers].length == 0
|
67
|
+
PrcLib.high_level_msg("\nBuilding your forge...\n")
|
68
|
+
process_create(:internet_server)
|
69
|
+
else
|
70
|
+
load_existing_forge(o_forge)
|
71
|
+
end
|
72
|
+
end
|
121
73
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
else
|
127
|
-
oForge[:servers].each { | oServerToFind |
|
128
|
-
Get(:server, oServerToFind[:id]) if /^maestro\./ =~ oServerToFind[:name]
|
129
|
-
}
|
130
|
-
PrcLib.high_level_msg ("\nChecking your forge...\n")
|
131
|
-
oServer = DataObjects(:server, :ObjectData)
|
132
|
-
if oServer
|
133
|
-
oIP = Query(:public_ip, :server_id => oServer[:id])
|
134
|
-
if oIP.length > 0
|
135
|
-
register oIP[0]
|
136
|
-
end
|
137
|
-
Create(:keypairs)
|
138
|
-
else
|
139
|
-
PrcLib.high_level_msg ("\nYour forge exist, without maestro. Building Maestro...\n")
|
140
|
-
Create(:internet_server)
|
141
|
-
|
142
|
-
PrcLib.high_level_msg ("\nBuilding your forge...\n")
|
143
|
-
end
|
74
|
+
def load_existing_forge(o_forge)
|
75
|
+
o_forge[:servers].each do |oServerToFind|
|
76
|
+
if /^maestro\./ =~ oServerToFind[:name]
|
77
|
+
process_get(:server, oServerToFind[:id])
|
144
78
|
end
|
79
|
+
end
|
80
|
+
PrcLib.high_level_msg("\nChecking your forge...\n")
|
81
|
+
|
82
|
+
o_server = data_objects(:server, :ObjectData)
|
83
|
+
if o_server
|
84
|
+
o_ip = process_query(:public_ip, :server_id => o_server[:id])
|
85
|
+
register o_ip[0] if o_ip.length > 0
|
86
|
+
process_create(:keypairs)
|
87
|
+
else
|
88
|
+
PrcLib.high_level_msg("\nYour forge exist, without maestro." \
|
89
|
+
" Building Maestro...\n")
|
90
|
+
process_create(:internet_server)
|
91
|
+
|
92
|
+
PrcLib.high_level_msg("\nBuilding your forge...\n")
|
93
|
+
end
|
94
|
+
end
|
145
95
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
96
|
+
def boot_keypairs(o_server)
|
97
|
+
# Get keypairs
|
98
|
+
h_keys = keypair_detect(
|
99
|
+
o_server[:key_name],
|
100
|
+
File.join(Forj.keypairs_path, o_server[:key_name])
|
101
|
+
)
|
102
|
+
|
103
|
+
private_key_file = File.join(
|
104
|
+
h_keys[:keypair_path],
|
105
|
+
h_keys[:private_key_name]
|
106
|
+
)
|
107
|
+
# public_key_file = File.join(
|
108
|
+
# h_keys[:keypair_path],
|
109
|
+
# h_keys[:public_key_name]
|
110
|
+
# )
|
111
|
+
|
112
|
+
o_server_key = process_get(:keypairs, o_server[:key_name])
|
113
|
+
|
114
|
+
keypair_coherent = coherent_keypair?(h_keys, o_server_key)
|
115
|
+
boot_options = { :keys => private_key_file, :coherent => keypair_coherent }
|
116
|
+
boot_options
|
117
|
+
end
|
157
118
|
|
158
|
-
|
159
|
-
|
119
|
+
def active_server?(o_server, o_address, private_key_file,
|
120
|
+
keypair_coherent, s_status
|
121
|
+
)
|
122
|
+
if o_server[:attrs][:status] == :active
|
123
|
+
s_msg = <<-END
|
124
|
+
Your forj Maestro server is up and running and is publically accessible
|
125
|
+
through IP '%s'.
|
126
|
+
|
127
|
+
You can connect to '%s' with:
|
128
|
+
ssh ubuntu@%s -o StrictHostKeyChecking=no -i %s
|
129
|
+
END
|
130
|
+
s_msg = format(s_msg, o_address[:public_ip], o_server[:name],
|
131
|
+
o_address[:public_ip], private_key_file
|
132
|
+
)
|
133
|
+
|
134
|
+
unless keypair_coherent
|
135
|
+
s_msg += "\n" + ANSI.bold(
|
136
|
+
'Unfortunatelly'
|
137
|
+
) + ' your current keypair is not usable to connect to your server.' \
|
138
|
+
"\n" + 'You need to fix this issue to gain access to your server.'
|
139
|
+
end
|
140
|
+
PrcLib.info(s_msg)
|
160
141
|
|
161
|
-
|
162
|
-
|
142
|
+
o_log = process_get(:server_log, 25)[:attrs][:output]
|
143
|
+
if /cloud-init boot finished/ =~ o_log
|
144
|
+
s_status = :active
|
145
|
+
PrcLib.high_level_msg("\n%s\nThe forge is ready...\n", s_msg)
|
146
|
+
else
|
147
|
+
PrcLib.high_level_msg("\n%s\nThe forge is still building...\n", s_msg)
|
148
|
+
s_status = :cloud_init
|
149
|
+
end
|
150
|
+
else
|
151
|
+
sleep 5
|
152
|
+
s_status = :starting
|
153
|
+
end
|
154
|
+
s_status
|
155
|
+
end
|
156
|
+
end
|
163
157
|
|
164
|
-
|
165
|
-
|
166
|
-
|
158
|
+
# Functions for boot - build_forge
|
159
|
+
class ForjCoreProcess
|
160
|
+
# rubocop:disable CyclomaticComplexity
|
161
|
+
def maestro_create_status(sStatus, iCurAct = 4)
|
162
|
+
s_activity = '/-\\|?'
|
163
|
+
if iCurAct < 4
|
164
|
+
s_cur_act = 'ACTIVE'
|
165
|
+
else
|
166
|
+
s_cur_act = ANSI.bold('PENDING')
|
167
|
+
end
|
168
|
+
|
169
|
+
case sStatus
|
170
|
+
when :checking
|
171
|
+
PrcLib.state('Checking server status')
|
172
|
+
when :starting
|
173
|
+
PrcLib.state('STARTING')
|
174
|
+
when :assign_ip
|
175
|
+
PrcLib.state('%s - %s - Assigning Public IP',
|
176
|
+
s_activity[iCurAct], s_cur_act)
|
177
|
+
when :cloud_init
|
178
|
+
PrcLib.state('%s - %s - Currently running cloud-init. Be patient.',
|
179
|
+
s_activity[iCurAct], s_cur_act)
|
180
|
+
when :nonet
|
181
|
+
PrcLib.state('%s - %s - Currently running cloud-init. Be patient.',
|
182
|
+
s_activity[iCurAct], s_cur_act)
|
183
|
+
when :restart
|
184
|
+
PrcLib.state('RESTARTING - Currently restarting maestro box. Be patient.')
|
185
|
+
when :active
|
186
|
+
PrcLib.info('Server is active')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
# rubocop:enable CyclomaticComplexity
|
190
|
+
|
191
|
+
def till_server_active(s_status, o_server, o_address, boot_options)
|
192
|
+
m_cloud_init_error = []
|
193
|
+
i_cur_act = 0
|
194
|
+
o_old_log = ''
|
195
|
+
|
196
|
+
while s_status != :active
|
197
|
+
maestro_create_status(s_status, i_cur_act)
|
198
|
+
i_cur_act += 1
|
199
|
+
i_cur_act = i_cur_act % 4
|
200
|
+
o_server = load_server(o_server)
|
201
|
+
# s_status = o_server[:attrs][:status]
|
202
|
+
if s_status == :starting
|
203
|
+
s_status = :assign_ip if o_server[:attrs][:status] == :active
|
204
|
+
elsif s_status == :assign_ip
|
205
|
+
s_status = assign_ip_boot(o_address, boot_options, s_status, o_server)
|
206
|
+
else # analyze the log output
|
207
|
+
output_options = { :status => s_status, :error => m_cloud_init_error,
|
208
|
+
:old_log => o_old_log, :cur_act => i_cur_act
|
209
|
+
}
|
210
|
+
output_options = analyze_log_output(output_options, s_status)
|
211
|
+
s_status = output_options[:status]
|
212
|
+
m_cloud_init_error = output_options[:error]
|
213
|
+
o_old_log = output_options[:old_log]
|
214
|
+
i_cur_act = output_options[:cur_act]
|
215
|
+
end
|
216
|
+
sleep(5) if s_status != :active
|
217
|
+
end
|
218
|
+
end
|
167
219
|
|
168
|
-
|
169
|
-
|
170
|
-
|
220
|
+
# Function to get the server, tracking errors
|
221
|
+
#
|
222
|
+
# *return*
|
223
|
+
# - Server found.
|
224
|
+
#
|
225
|
+
def load_server(server)
|
226
|
+
begin
|
227
|
+
found_server = process_get(:server, server[:attrs][:id])
|
228
|
+
rescue => e
|
229
|
+
PrcLib.error(e.message)
|
230
|
+
end
|
231
|
+
(found_server.nil? ? server : found_server)
|
232
|
+
end
|
233
|
+
end
|
171
234
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
sStatus = :active
|
183
|
-
PrcLib.high_level_msg ("\n%s\nThe forge is ready...\n" % sMsg)
|
184
|
-
else
|
185
|
-
PrcLib.high_level_msg ("\n%s\nThe forge is still building...\n" % sMsg)
|
186
|
-
sStatus = :cloud_init
|
187
|
-
end
|
235
|
+
# Functions for boot - build_forge
|
236
|
+
class ForjCoreProcess
|
237
|
+
def assign_ip_boot(o_address, boot_options, s_status, o_server)
|
238
|
+
if o_address.empty?
|
239
|
+
# To be able to ask for server IP assigned
|
240
|
+
query_cache_cleanup(:public_ip)
|
241
|
+
o_addresses = process_query(:public_ip, :server_id => o_server[:id])
|
242
|
+
if o_addresses.length == 0
|
243
|
+
# Assigning Public IP.
|
244
|
+
o_address = process_create(:public_ip)
|
188
245
|
else
|
189
|
-
|
190
|
-
sStatus = :starting
|
246
|
+
o_address = o_addresses[0]
|
191
247
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
while sStatus != :active
|
198
|
-
maestro_create_status(sStatus, iCurAct)
|
199
|
-
iCurAct += 1
|
200
|
-
iCurAct = iCurAct % 4
|
201
|
-
begin
|
202
|
-
oServer = Get(:server, oServer[:attrs][:id])
|
203
|
-
rescue => e
|
204
|
-
PrcLib.error(e.message)
|
205
|
-
end
|
206
|
-
if sStatus == :starting
|
207
|
-
if oServer[:attrs][:status] == :active
|
208
|
-
sStatus = :assign_ip
|
209
|
-
end
|
210
|
-
elsif sStatus == :assign_ip
|
211
|
-
if oAddress.empty?
|
212
|
-
query_cache_cleanup(:public_ip) # To be able to ask for server IP assigned
|
213
|
-
oAddresses = Query(:public_ip, :server_id => oServer[:id])
|
214
|
-
if oAddresses.length == 0
|
215
|
-
# Assigning Public IP.
|
216
|
-
oAddress = Create(:public_ip)
|
217
|
-
else
|
218
|
-
oAddress = oAddresses[0]
|
219
|
-
end
|
220
|
-
end
|
221
|
-
sMsg = <<-END
|
222
|
-
Public IP for server '#{oServer[:name]}' is assigned.
|
223
|
-
Now, as soon as the server respond to the ssh port, you will be able to get a tail of the build with:
|
248
|
+
end
|
249
|
+
s_msg = <<-END
|
250
|
+
Public IP for server '%s' is assigned.
|
251
|
+
Now, as soon as the server respond to the ssh port,
|
252
|
+
you will be able to get a tail of the build with:
|
224
253
|
while [ 1 = 1 ]
|
225
254
|
do
|
226
|
-
|
227
|
-
|
255
|
+
ssh ubuntu@%s -o StrictHostKeyChecking=no -i %s tail -f /var/log/cloud-init.log
|
256
|
+
sleep 5
|
228
257
|
done
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
PrcLib.high_level_msg ("Critical error cleared. Cloud-init seems moving...")
|
244
|
-
PrcLib.info ("Critical error cleared. Cloud-init seems moving...")
|
245
|
-
mCloudInitError = []
|
246
|
-
end
|
247
|
-
elsif /\[CRITICAL\]/ =~ oLog
|
248
|
-
mCritical = oLog.scan(/.*\[CRITICAL\].*\n/)
|
249
|
-
if not (mCloudInitError == mCritical)
|
250
|
-
sReported = oLog.clone
|
251
|
-
sReported['CRITICAL'] = ANSI.bold('CRITICAL')
|
252
|
-
PrcLib.error("cloud-init error detected:\n-----\n%s\n-----\nPlease connect to the box to decide what you need to do." % [sReported])
|
253
|
-
mCloudInitError = mCritical
|
254
|
-
end
|
255
|
-
elsif sStatus == :cloud_init and /cloud-init-nonet gave up waiting for a network device/ =~ oLog
|
256
|
-
# Valid for ubuntu image 12.04
|
257
|
-
PrcLib.warning("Cloud-init has gave up to configure the network. waiting...")
|
258
|
-
sStatus = :nonet
|
259
|
-
elsif sStatus == :nonet and /Booting system without full network configuration/ =~ oLog
|
260
|
-
# Valid for ubuntu image 12.04
|
261
|
-
PrcLib.warning("forj has detected an issue to bring up your maestro server. Removing it and re-creating a new one. please be patient...")
|
262
|
-
sStatus = :restart
|
263
|
-
elsif sStatus == :restart
|
264
|
-
Delete(:server)
|
265
|
-
Create(:internet_server)
|
266
|
-
sStatus = :starting
|
267
|
-
end
|
268
|
-
end
|
269
|
-
sleep(5) if sStatus != :active
|
270
|
-
end
|
258
|
+
END
|
259
|
+
s_msg = format(s_msg, o_server[:name],
|
260
|
+
o_address[:public_ip], boot_options[:keys]
|
261
|
+
)
|
262
|
+
unless boot_options[:coherent]
|
263
|
+
s_msg += ANSI.bold("\nUnfortunatelly") + " your current keypair' \
|
264
|
+
' is not usable to connect to your server.\nYou need to fix' \
|
265
|
+
' this issue to gain access to your server."
|
266
|
+
end
|
267
|
+
PrcLib.info(s_msg)
|
268
|
+
PrcLib.high_level_msg("\n%s\nThe forge is still building...\n", s_msg)
|
269
|
+
s_status = :cloud_init
|
270
|
+
s_status
|
271
|
+
end
|
271
272
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
273
|
+
def analyze_log_output(output_options, s_status)
|
274
|
+
# m_cloud_init_error = []
|
275
|
+
# o_old_log = ''
|
276
|
+
o_log = process_get(:server_log, 25)[:attrs][:output]
|
277
|
+
# i_cur_act = 4 if o_log == o_old_log
|
278
|
+
output_options[:cur_act] = 4 if o_log == output_options[:old_log]
|
279
|
+
# o_old_log = o_log
|
280
|
+
output_options[:old_log] = o_log
|
281
|
+
if /cloud-init boot finished/ =~ o_log
|
282
|
+
# s_status = :active
|
283
|
+
output_options[:status] = :active
|
284
|
+
output_options[:error] = display_boot_moving_error(
|
285
|
+
output_options[:error]
|
286
|
+
)
|
287
|
+
elsif /\[CRITICAL\]/ =~ o_log
|
288
|
+
m_critical = o_log.scan(/.*\[CRITICAL\].*\n/)
|
289
|
+
output_options[:error] = display_boot_critical_error(
|
290
|
+
output_options[:error],
|
291
|
+
m_critical
|
292
|
+
)
|
293
|
+
else
|
294
|
+
# validate server status
|
295
|
+
output_options = analyze_server_status(s_status, o_log, output_options)
|
296
|
+
end
|
297
|
+
output_options
|
298
|
+
end
|
299
|
+
|
300
|
+
def display_boot_critical_error(m_cloud_init_error, m_critical)
|
301
|
+
# unless (m_cloud_init_error == m_critical)
|
302
|
+
return if m_cloud_init_error == m_critical
|
303
|
+
s_reported = o_log.clone
|
304
|
+
s_reported['CRITICAL'] = ANSI.bold('CRITICAL')
|
305
|
+
PrcLib.error("cloud-init error detected:\n-----\n%s\n-----\n" \
|
306
|
+
'Please connect to the box to decide what you' \
|
307
|
+
' need to do.', s_reported)
|
308
|
+
m_cloud_init_error = m_critical
|
309
|
+
m_cloud_init_error
|
310
|
+
# end
|
311
|
+
end
|
312
|
+
|
313
|
+
def display_boot_moving_error(m_cloud_init_error)
|
314
|
+
if m_cloud_init_error != []
|
315
|
+
PrcLib.high_level_msg(
|
316
|
+
'Critical error cleared. Cloud-init seems moving...'
|
317
|
+
)
|
318
|
+
PrcLib.info('Critical error cleared. Cloud-init seems moving...')
|
319
|
+
m_cloud_init_error = []
|
320
|
+
end
|
321
|
+
m_cloud_init_error
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# Functions for boot - build_forge
|
326
|
+
class ForjCoreProcess
|
327
|
+
def analyze_server_status(s_status, o_log, output_options)
|
328
|
+
if s_status == :cloud_init &&
|
329
|
+
/cloud-init-nonet gave up waiting for a network device/ =~ o_log
|
330
|
+
# Valid for ubuntu image 12.04
|
331
|
+
PrcLib.warning(
|
332
|
+
'Cloud-init has gave up to configure the network. waiting...'
|
333
|
+
)
|
334
|
+
output_options[:status] = :nonet
|
335
|
+
elsif s_status == :nonet &&
|
336
|
+
/Booting system without full network configuration/ =~ o_log
|
337
|
+
# Valid for ubuntu image 12.04
|
338
|
+
PrcLib.warning(
|
339
|
+
'forj has detected an issue to bring up your maestro server.' \
|
340
|
+
' Removing it and re-creating a new one. please be patient...'
|
341
|
+
)
|
342
|
+
output_options[:status] = :restart
|
343
|
+
elsif s_status == :restart
|
344
|
+
process_delete(:server)
|
345
|
+
process_create(:internet_server)
|
346
|
+
output_options[:status] = :starting
|
347
|
+
end
|
348
|
+
output_options
|
349
|
+
end
|
350
|
+
|
351
|
+
def read_blueprint_implemented(o_forge, o_address)
|
352
|
+
s_msg = format(
|
353
|
+
"Your Forge '%s' is ready and accessible from" \
|
354
|
+
" IP #{o_address[:public_ip]}.",
|
355
|
+
config[:instance_name]
|
356
|
+
)
|
357
|
+
# TODO: read the blueprint/layout to identify which services
|
358
|
+
# are implemented and can be accessible.
|
359
|
+
if config[:blueprint]
|
360
|
+
s_msg += format(
|
361
|
+
"\n" + 'Maestro has implemented the following server(s) for your' \
|
362
|
+
" blueprint '%s':",
|
363
|
+
config[:blueprint]
|
364
|
+
)
|
365
|
+
server_options = display_servers_with_ip(o_forge, s_msg)
|
366
|
+
s_msg += server_options[:message]
|
367
|
+
i_count = server_options[:count]
|
368
|
+
if i_count > 0
|
369
|
+
s_msg += format("\n%d server(s) identified.\n", i_count)
|
296
370
|
else
|
297
|
-
|
371
|
+
s_msg = 'No servers found except maestro'
|
372
|
+
PrcLib.warning(
|
373
|
+
format(
|
374
|
+
'Something went wrong, while creating nodes for blueprint' \
|
375
|
+
" '%s'. check maestro logs.",
|
376
|
+
config[:blueprint]
|
377
|
+
)
|
378
|
+
)
|
298
379
|
end
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
380
|
+
else
|
381
|
+
s_msg += "\nMaestro has NOT implemented any servers, because you did" \
|
382
|
+
' not provided a blueprint. Connect to Maestro, and ask Maestro to' \
|
383
|
+
' implement any kind of blueprint you need. (Feature currently' \
|
384
|
+
' under development)'
|
385
|
+
end
|
386
|
+
PrcLib.info(s_msg)
|
387
|
+
PrcLib.high_level_msg("\n%s\nEnjoy!\n", s_msg)
|
388
|
+
end
|
389
|
+
|
390
|
+
def display_servers_with_ip(o_forge, s_msg)
|
391
|
+
i_count = 0
|
392
|
+
o_forge[:servers].each do |server|
|
393
|
+
next if /^maestro\./ =~ server[:name]
|
394
|
+
register(server)
|
395
|
+
o_ip = process_query(:public_ip, :server_id => server[:id])
|
396
|
+
if o_ip.length == 0
|
397
|
+
s_msg += format("\n- %s (No public IP)", server[:name])
|
308
398
|
else
|
309
|
-
|
399
|
+
s_msg += format("\n- %s (%s)", server[:name], o_ip[0][:public_ip])
|
310
400
|
end
|
401
|
+
i_count += 1
|
402
|
+
end
|
403
|
+
server_options = { :message => s_msg, :count => i_count }
|
404
|
+
server_options
|
405
|
+
end
|
406
|
+
end
|
311
407
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
408
|
+
# Functions for boot - build_metadata
|
409
|
+
class ForjCoreProcess
|
410
|
+
def load_encoded_key
|
411
|
+
key_file = File.join(PrcLib.pdata_path, '.key')
|
412
|
+
if !File.exist?(key_file)
|
413
|
+
# Need to create a random key.
|
414
|
+
entr = {
|
415
|
+
:key => rand(36**10).to_s(36),
|
416
|
+
:salt => Time.now.to_i.to_s,
|
417
|
+
:iv => Base64.strict_encode64(
|
418
|
+
OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
|
419
|
+
)
|
420
|
+
}
|
421
|
+
|
422
|
+
PrcLib.debug("Writing '%s' key file", key_file)
|
423
|
+
File.open(key_file, 'w') do |out|
|
424
|
+
out.write(Base64.encode64(entr.to_yaml))
|
327
425
|
end
|
328
|
-
|
426
|
+
else
|
427
|
+
PrcLib.debug("Loading '%s' key file", key_file)
|
428
|
+
encoded_key = IO.read(key_file)
|
429
|
+
entr = YAML.load(Base64.decode64(encoded_key))
|
430
|
+
end
|
431
|
+
entr
|
432
|
+
end
|
329
433
|
|
330
|
-
|
434
|
+
def decrypt_key(os_enckey, entr)
|
435
|
+
begin
|
436
|
+
os_key = Encryptor.decrypt(
|
437
|
+
:value => Base64.strict_decode64(os_enckey),
|
438
|
+
:key => entr[:key],
|
439
|
+
:iv => Base64.strict_decode64(entr[:iv]),
|
440
|
+
:salt => entr[:salt]
|
441
|
+
)
|
442
|
+
rescue
|
443
|
+
raise 'Unable to decript your password. You need to re-execute setup.'
|
444
|
+
end
|
445
|
+
os_key
|
446
|
+
end
|
331
447
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
448
|
+
def load_hpcloud(hParams, os_key)
|
449
|
+
hpcloud_priv = nil
|
450
|
+
IO.popen('gzip -c', 'r+') do|pipe|
|
451
|
+
pipe.puts(format('HPCLOUD_OS_USER=%s', hParams[:os_user]))
|
452
|
+
pipe.puts(format('HPCLOUD_OS_KEY=%s', os_key))
|
453
|
+
pipe.puts(format('DNS_KEY=%s', hParams[:account_id]))
|
454
|
+
pipe.puts(format('DNS_SECRET=%s', hParams[:account_key]))
|
455
|
+
pipe.close_write
|
456
|
+
hpcloud_priv = pipe.read
|
457
|
+
end
|
458
|
+
hpcloud_priv
|
459
|
+
end
|
336
460
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
end
|
357
|
-
oMaestro = register(hResult, sObjectType)
|
358
|
-
oMaestro[:maestro_repo] = hResult[:maestro_repo]
|
359
|
-
oMaestro
|
360
|
-
end
|
461
|
+
def load_h_meta(hParams, hpcloud_priv)
|
462
|
+
h_meta = {
|
463
|
+
'cdksite' => config.get(:server_name),
|
464
|
+
'cdkdomain' => hParams[:domain_name],
|
465
|
+
'eroip' => '127.0.0.1',
|
466
|
+
'erosite' => config.get(:server_name),
|
467
|
+
'erodomain' => hParams[:domain_name],
|
468
|
+
'gitbranch' => hParams[:branch],
|
469
|
+
'security_groups' => hParams[:security_group],
|
470
|
+
'tenant_name' => hParams[:tenant_name],
|
471
|
+
'network_name' => hParams[:network_name],
|
472
|
+
'hpcloud_os_region' => hParams[:compute],
|
473
|
+
'PUPPET_DEBUG' => 'True',
|
474
|
+
'image_name' => hParams[:image_name],
|
475
|
+
'key_name' => hParams[:keypair_name],
|
476
|
+
'hpcloud_priv' => Base64.strict_encode64(
|
477
|
+
hpcloud_priv
|
478
|
+
).gsub('=', '') # Remove pad
|
479
|
+
}
|
361
480
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
481
|
+
if hParams[:dns_service]
|
482
|
+
h_meta['dns_zone'] = hParams[:dns_service]
|
483
|
+
h_meta['dns_tenantid'] = hParams[:dns_tenant_id]
|
484
|
+
end
|
485
|
+
# If requested by user, ask Maestro to instantiate a blueprint.
|
486
|
+
h_meta['blueprint'] = hParams[:blueprint] if hParams[:blueprint]
|
487
|
+
|
488
|
+
# Add init additionnal git clone steps.
|
489
|
+
h_meta['repos'] = hParams[:repos] if hParams[:repos]
|
490
|
+
# Add init bootstrap additionnal steps
|
491
|
+
h_meta['bootstrap'] = hParams[:bootstrap] if hParams[:bootstrap]
|
492
|
+
h_meta
|
493
|
+
end
|
369
494
|
|
370
|
-
|
495
|
+
def build_metadata(sObjectType, hParams)
|
496
|
+
entr = load_encoded_key
|
371
497
|
|
372
|
-
|
498
|
+
os_enckey = hParams[:os_enckey]
|
373
499
|
|
374
|
-
|
500
|
+
os_key = decrypt_key(os_enckey, entr)
|
375
501
|
|
376
|
-
|
377
|
-
PrcLib.state("Building your infra workspace in '%s'" % [infra])
|
502
|
+
hpcloud_priv = load_hpcloud(hParams, os_key)
|
378
503
|
|
379
|
-
|
380
|
-
|
504
|
+
config.set(
|
505
|
+
:server_name,
|
506
|
+
format('maestro.%s', hParams[:instance_name])
|
507
|
+
) # Used by :server object
|
381
508
|
|
382
|
-
|
383
|
-
File.write(file_ver, $INFRA_VERSION)
|
384
|
-
PrcLib.info("The infra workspace '%s' has been built from maestro predefined files." % [infra])
|
385
|
-
else
|
386
|
-
PrcLib.info("Re-using your infra... in '%s'" % [infra])
|
387
|
-
end
|
509
|
+
h_meta = load_h_meta(hParams, hpcloud_priv)
|
388
510
|
|
511
|
+
config.set(:meta_data, h_meta) # Used by :server object
|
389
512
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
end
|
394
|
-
|
395
|
-
# Function which compare directories from maestro templates to infra.
|
396
|
-
def infra_is_original?(infra_dir, maestro_dir)
|
397
|
-
dest_cloud_init = File.join(infra_dir, 'cloud-init')
|
398
|
-
template = File.join(maestro_dir, 'templates', 'infra')
|
399
|
-
sMD5List = File.join(infra_dir, '.maestro_original.yaml')
|
400
|
-
bResult = true
|
401
|
-
hResult = {}
|
402
|
-
if File.exists?(sMD5List)
|
403
|
-
begin
|
404
|
-
hResult = YAML.load_file(sMD5List)
|
405
|
-
rescue => e
|
406
|
-
PrcLib.error("Unable to load valid Original files list '%s'. Your infra workspace won't be migrated, until fixed." % sMD5List)
|
407
|
-
bResult = false
|
408
|
-
end
|
409
|
-
if not hResult
|
410
|
-
hResult = {}
|
411
|
-
bResult = false
|
412
|
-
end
|
413
|
-
end
|
414
|
-
# We are taking care on bootstrap files only.
|
415
|
-
Find.find(File.join(template, 'cloud-init')) { | path |
|
416
|
-
if not File.directory?(path)
|
417
|
-
sMaestroRelPath = path.clone
|
418
|
-
sMaestroRelPath[File.join(template, 'cloud-init/')] = ""
|
419
|
-
sInfra_path = File.join(dest_cloud_init, sMaestroRelPath)
|
420
|
-
if File.exists?(sInfra_path)
|
421
|
-
md5_file = Digest::MD5.file(sInfra_path).hexdigest
|
422
|
-
if hResult.key?(sMaestroRelPath) and hResult[sMaestroRelPath] != md5_file
|
423
|
-
bResult = false
|
424
|
-
PrcLib.info("'%s' infra file has changed from original template in maestro." % sInfra_path)
|
425
|
-
else
|
426
|
-
PrcLib.debug("'%s' infra file has not been updated." % sInfra_path)
|
427
|
-
end
|
428
|
-
end
|
429
|
-
md5_file = Digest::MD5.file(path).hexdigest
|
430
|
-
hResult[sMaestroRelPath] = md5_file
|
431
|
-
end
|
432
|
-
}
|
433
|
-
begin
|
434
|
-
File.open(sMD5List, 'w') do |out|
|
435
|
-
YAML.dump(hResult, out)
|
436
|
-
end
|
437
|
-
rescue => e
|
438
|
-
PrcLib.error("%s\n%s" % [e.message, e.backtrace.join("\n")])
|
439
|
-
end
|
440
|
-
if bResult
|
441
|
-
PrcLib.debug("No original files found has been updated. Infra workspace can be updated/created if needed.")
|
442
|
-
else
|
443
|
-
PrcLib.warning("At least, one file has been updated. Infra workspace won't be updated by forj cli.")
|
444
|
-
end
|
445
|
-
bResult
|
446
|
-
end
|
513
|
+
h_meta_printable = h_meta.clone
|
514
|
+
h_meta_printable['hpcloud_priv'] = 'XXX - data hidden - XXX'
|
515
|
+
PrcLib.info("Metadata set:\n%s", h_meta_printable)
|
447
516
|
|
448
|
-
|
449
|
-
|
517
|
+
o_meta_data = register(h_meta, sObjectType)
|
518
|
+
o_meta_data[:meta_data] = h_meta
|
450
519
|
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
def old_infra_data_update(oConfig, version, infra_dir)
|
464
|
-
PrcLib.info("Migrating your local infra repo (%s) to the latest version." % version)
|
465
|
-
bRebuild = false # Be default migration is successful. No need to rebuild it.
|
466
|
-
case version
|
467
|
-
when '0.0.36'
|
468
|
-
# Moving from 0.0.36 or less to 0.0.37 or higher.
|
469
|
-
# SET_COMPUTE="{SET_COMPUTE!}" => Setting for Compute. ignored. Coming from HPC
|
470
|
-
# SET_TENANT_NAME="{SET_TENANT_NAME!}" => Setting for Compute. ignored. Need to query HPC from current Tenant ID
|
471
|
-
|
472
|
-
# SET_DNS_TENANTID="{SET_DNS_TENANTID!}" => Setting for DNS. meta = dns_tenantid
|
473
|
-
# ==> :forj_accounts, sAccountName, :dns, :tenant_id
|
474
|
-
|
475
|
-
# SET_DNS_ZONE="{SET_DNS_ZONE!}" => Setting for DNS. meta = dns_zone
|
476
|
-
# ==> :forj_accounts, sAccountName, :dns, :service
|
477
|
-
|
478
|
-
# SET_DOMAIN="{SET_DOMAIN!}" => Setting for Maestro (required) and DNS if enabled.
|
479
|
-
# ==> :forj_accounts, sAccountName, :dns, :domain_name
|
480
|
-
sAccountName = oConfig.get(:account_name)
|
481
|
-
|
482
|
-
yDns = {}
|
483
|
-
yDns = oConfig.oConfig.ExtraGet(:forj_accounts, sAccountName, :dns) if oConfig.oConfig.ExtraExist?(:forj_accounts, sAccountName, :dns)
|
484
|
-
Dir.foreach(infra_dir) do | file |
|
485
|
-
next if not /^maestro\.box\..*\.env$/ =~ file
|
486
|
-
build_env = File.join(infra_dir, file)
|
487
|
-
PrcLib.debug("Reading data from '%s'" % build_env)
|
488
|
-
tags = {'SET_DNS_TENANTID' => :tenant_id,
|
489
|
-
'SET_DNS_ZONE' => :service,
|
490
|
-
'SET_DOMAIN' => :domain_name
|
491
|
-
}
|
492
|
-
begin
|
493
|
-
bUpdate = nil
|
494
|
-
|
495
|
-
File.open(build_env) do |f|
|
496
|
-
f.each_line do |line|
|
497
|
-
mObj = line.match(/^(SET_[A-Z_]+)=["'](.*)["'].*$/)
|
498
|
-
if mObj
|
499
|
-
PrcLib.debug("Reviewing detected '%s' tag" % [mObj[1]])
|
500
|
-
tag = (tags[mObj[1]]? tags[mObj[1]] : nil)
|
501
|
-
if tag and mObj[2]
|
502
|
-
if bUpdate == nil and rhGet(yDns, tag) and rhGet(yDns, tag) != mObj[2]
|
503
|
-
PrcLib.message("Your account setup is different than build env.")
|
504
|
-
PrcLib.message("We suggest you to update your account setup with data from your build env.")
|
505
|
-
bUpdate = agree("Do you want to update your setup with those build environment data?")
|
506
|
-
end
|
507
|
-
if bUpdate != nil and bUpdate
|
508
|
-
PrcLib.debug("Saved: '%s' = '%s'" % [mObj[1],mObj[2]])
|
509
|
-
rhSet(yDns, mObj[2], tag)
|
510
|
-
end
|
511
|
-
end
|
512
|
-
end
|
513
|
-
end
|
514
|
-
end
|
515
|
-
rescue => e
|
516
|
-
PrcLib.fatal(1, "Failed to open the build environment file '%s'" % build_env, e)
|
517
|
-
end
|
518
|
-
end
|
519
|
-
file_ver = File.join(infra_dir, 'forj-cli.ver')
|
520
|
-
File.write(file_ver, $INFRA_VERSION)
|
521
|
-
oConfig.oConfig.ExtraSet(:forj_accounts, sAccountName, :dns, yDns)
|
522
|
-
oConfig.oConfig.ExtraSave(File.join($FORJ_ACCOUNTS_PATH, sAccountName), :forj_accounts, sAccountName)
|
523
|
-
return bRebuild
|
520
|
+
o_meta_data
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
# Functions for boot - clone_or_use_maestro_repo
|
525
|
+
class ForjCoreProcess
|
526
|
+
def clone_maestro_repo(maestro_url, path_maestro, config)
|
527
|
+
PrcLib.state("Cloning maestro repo from '%s' to '%s'",
|
528
|
+
maestro_url, File.join(path_maestro, 'maestro'))
|
529
|
+
if File.directory?(path_maestro)
|
530
|
+
if File.directory?(File.join(path_maestro, 'maestro'))
|
531
|
+
FileUtils.rm_r File.join(path_maestro, 'maestro')
|
524
532
|
end
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
# generate boot_*.sh
|
545
|
-
mime_cmd = "#{build_tmpl_dir}/write-mime-multipart.py"
|
546
|
-
bootstrap = "#{build_tmpl_dir}/bootstrap_build.sh"
|
547
|
-
|
548
|
-
cmd = "%s '%s' '%s' '%s' '%s' '%s' '%s' '%s'" % [
|
549
|
-
bootstrap, # script
|
550
|
-
$FORJ_DATA_PATH, # $1 = Forj data base dir
|
551
|
-
hParams[:maestro_repository, :maestro_repo], # $2 = Maestro repository dir
|
552
|
-
config[:bootstrap_dirs], # $3 = Bootstrap directories
|
553
|
-
config[:bootstrap_extra_dir], # $4 = Bootstrap extra directory
|
554
|
-
meta_data, # $5 = meta_data (string)
|
555
|
-
mime_cmd, # $6: mime script file to execute.
|
556
|
-
mime # $7: mime file generated.
|
557
|
-
]
|
558
|
-
|
559
|
-
# TODO: Replace shell script call to ruby functions
|
560
|
-
if $LIB_FORJ_DEBUG >= 1
|
561
|
-
cmd += " >> #{$FORJ_DATA_PATH}/forj.log"
|
533
|
+
end
|
534
|
+
git = Git.clone(maestro_url, 'maestro', :path => path_maestro)
|
535
|
+
git.checkout(config[:branch]) if config[:branch] != 'master'
|
536
|
+
PrcLib.info("Maestro repo '%s' cloned on branch '%s'",
|
537
|
+
File.join(path_maestro, 'maestro'), config[:branch])
|
538
|
+
end
|
539
|
+
|
540
|
+
def clone_or_use_maestro_repo(sObjectType, hParams)
|
541
|
+
maestro_url = hParams[:maestro_url]
|
542
|
+
maestro_repo = File.expand_path(
|
543
|
+
hParams[:maestro_repo]
|
544
|
+
) unless hParams[:maestro_repo].nil?
|
545
|
+
path_maestro = File.expand_path('~/.forj/')
|
546
|
+
h_result = {}
|
547
|
+
|
548
|
+
begin
|
549
|
+
if maestro_repo && File.directory?(maestro_repo)
|
550
|
+
PrcLib.info("Using maestro repo '%s'", maestro_repo)
|
551
|
+
h_result[:maestro_repo] = maestro_repo
|
562
552
|
else
|
563
|
-
|
553
|
+
h_result[:maestro_repo] = File.join(path_maestro, 'maestro')
|
554
|
+
clone_maestro_repo(maestro_url, path_maestro, config)
|
564
555
|
end
|
565
|
-
|
566
|
-
|
567
|
-
|
556
|
+
rescue => e
|
557
|
+
PrcLib.error('Error while cloning the repo from %s\n%s\n%s',
|
558
|
+
maestro_url, e.message, e.backtrace.join("\n"))
|
559
|
+
PrcLib.info(
|
560
|
+
'If this error persist you could clone the repo manually in ~/.forj/'
|
561
|
+
)
|
562
|
+
end
|
563
|
+
o_maestro = register(h_result, sObjectType)
|
564
|
+
o_maestro[:maestro_repo] = h_result[:maestro_repo]
|
565
|
+
o_maestro
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
# Functions for boot - create_or_use_infra
|
570
|
+
class ForjCoreProcess
|
571
|
+
def create_or_use_infra(sObjectType, hParams)
|
572
|
+
infra = File.expand_path(hParams[:infra_repo])
|
573
|
+
maestro_repo = hParams[:maestro_repository, :maestro_repo]
|
574
|
+
# branch = hParams[:branch]
|
575
|
+
dest_cloud_init = File.join(infra, 'cloud-init')
|
576
|
+
template = File.join(maestro_repo, 'templates', 'infra')
|
577
|
+
cloud_init = File.join(template, 'cloud-init')
|
568
578
|
|
569
|
-
|
579
|
+
h_infra = { :infra_repo => dest_cloud_init }
|
570
580
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
PrcLib.fatal(1, e.message)
|
575
|
-
end
|
576
|
-
if $LIB_FORJ_DEBUG < 5
|
577
|
-
File.delete(mime)
|
578
|
-
else
|
579
|
-
ForjLib.debug(5, "user_data temp file '%s' kept" % mime)
|
580
|
-
end
|
581
|
+
PrcLib.ensure_dir_exists(dest_cloud_init)
|
582
|
+
|
583
|
+
b_rebuild_infra = infra_is_original?(infra, maestro_repo)
|
581
584
|
|
582
|
-
|
585
|
+
if b_rebuild_infra
|
586
|
+
PrcLib.state("Building your infra workspace in '%s'", infra)
|
583
587
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
588
|
+
PrcLib.debug("Copying recursively '%s' to '%s'", cloud_init, infra)
|
589
|
+
FileUtils.copy_entry(cloud_init, dest_cloud_init)
|
590
|
+
|
591
|
+
file_ver = File.join(infra, 'forj-cli.ver')
|
592
|
+
File.write(file_ver, INFRA_VERSION)
|
593
|
+
PrcLib.info("The infra workspace '%s' has been built from maestro" \
|
594
|
+
' predefined files.', infra)
|
595
|
+
else
|
596
|
+
PrcLib.info("Re-using your infra... in '%s'", infra)
|
597
|
+
end
|
598
|
+
|
599
|
+
o_infra = register(h_infra, sObjectType)
|
600
|
+
o_infra[:infra_repo] = h_infra[:infra_repo]
|
601
|
+
o_infra
|
602
|
+
end
|
603
|
+
|
604
|
+
def load_infra(template, dest_cloud_init, h_result, b_result)
|
605
|
+
# We are taking care on bootstrap files only.
|
606
|
+
Find.find(File.join(template, 'cloud-init')) do |path|
|
607
|
+
# unless File.directory?(path)
|
608
|
+
next if File.directory?(path)
|
609
|
+
s_maestro_rel_path = path.clone
|
610
|
+
s_maestro_rel_path[File.join(template, 'cloud-init/')] = ''
|
611
|
+
s_infra_path = File.join(dest_cloud_init, s_maestro_rel_path)
|
612
|
+
if File.exist?(s_infra_path)
|
613
|
+
md5_file = Digest::MD5.file(s_infra_path).hexdigest
|
614
|
+
if h_result.key?(s_maestro_rel_path) &&
|
615
|
+
h_result[s_maestro_rel_path] != md5_file
|
616
|
+
b_result = false
|
617
|
+
PrcLib.info("'%s' infra file has changed from original template" \
|
618
|
+
' in maestro.', s_infra_path)
|
619
|
+
else
|
620
|
+
PrcLib.debug("'%s' infra file has not been updated.", s_infra_path)
|
621
|
+
end
|
622
|
+
end
|
623
|
+
md5_file = Digest::MD5.file(path).hexdigest
|
624
|
+
h_result[s_maestro_rel_path] = md5_file
|
625
|
+
# end
|
626
|
+
end
|
627
|
+
b_result
|
590
628
|
end
|
591
629
|
|
630
|
+
def open_md5(s_md5_list, h_result)
|
631
|
+
# begin
|
632
|
+
File.open(s_md5_list, 'w') do |out|
|
633
|
+
YAML.dump(h_result, out)
|
634
|
+
end
|
635
|
+
rescue => e
|
636
|
+
PrcLib.error("%s\n%s", e.message, e.backtrace.join("\n"))
|
637
|
+
# end
|
638
|
+
end
|
592
639
|
end
|
593
640
|
|
594
|
-
# Functions for
|
641
|
+
# Functions for boot - create_or_use_infra
|
595
642
|
class ForjCoreProcess
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
end
|
612
|
-
else
|
613
|
-
return false
|
614
|
-
end
|
643
|
+
# Function which compare directories from maestro templates to infra.
|
644
|
+
def infra_is_original?(infra_dir, maestro_dir)
|
645
|
+
dest_cloud_init = File.join(infra_dir, 'cloud-init')
|
646
|
+
template = File.join(maestro_dir, 'templates', 'infra')
|
647
|
+
s_md5_list = File.join(infra_dir, '.maestro_original.yaml')
|
648
|
+
b_result = true
|
649
|
+
h_result = {}
|
650
|
+
if File.exist?(s_md5_list)
|
651
|
+
begin
|
652
|
+
h_result = YAML.load_file(s_md5_list)
|
653
|
+
rescue
|
654
|
+
PrcLib.error("Unable to load valid Original files list '%s'. " \
|
655
|
+
"Your infra workspace won't be migrated, until fixed.",
|
656
|
+
s_md5_list)
|
657
|
+
b_result = false
|
615
658
|
end
|
616
|
-
|
617
|
-
|
659
|
+
unless h_result
|
660
|
+
h_result = {}
|
661
|
+
b_result = false
|
662
|
+
end
|
663
|
+
end
|
664
|
+
b_result = load_infra(template, dest_cloud_init, h_result, b_result)
|
665
|
+
open_md5(s_md5_list, h_result)
|
666
|
+
if b_result
|
667
|
+
PrcLib.debug(
|
668
|
+
'No original files found has been updated. Infra workspace' \
|
669
|
+
' can be updated/created if needed.'
|
670
|
+
)
|
671
|
+
else
|
672
|
+
PrcLib.warning(
|
673
|
+
'At least, one file has been updated. Infra workspace' \
|
674
|
+
" won't be updated by forj cli."
|
675
|
+
)
|
676
|
+
end
|
677
|
+
b_result
|
678
|
+
end
|
618
679
|
|
619
|
-
|
620
|
-
|
621
|
-
# Getting Account keypair information
|
622
|
-
key_name = config[:keypair_name]
|
623
|
-
key_path = File.expand_path(config[:keypair_files])
|
680
|
+
def infra_rebuild(infra_dir)
|
681
|
+
return false unless File.exist?(infra_dir)
|
624
682
|
|
625
|
-
|
626
|
-
|
627
|
-
|
683
|
+
file_ver = File.join(infra_dir, 'forj-cli.ver')
|
684
|
+
forj_infra_version = nil
|
685
|
+
forj_infra_version = File.read(file_ver) if File.exist?(file_ver)
|
628
686
|
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
end
|
637
|
-
new_key_name = new_key_name.to_s
|
638
|
-
sMsg = "Incorrect. You have to choose a keypair name different than '#{key_name}'. If you want to interrupt, press Ctrl-C and retry later.\nSo, please, provide a different keypair name:" if key_name == new_key_name
|
639
|
-
end
|
640
|
-
key_name = new_key_name
|
641
|
-
config.set(:key_name, key_name)
|
642
|
-
keys = keypair_detect(key_name, key_path)
|
643
|
-
end
|
687
|
+
if forj_infra_version.nil? || forj_infra_version == ''
|
688
|
+
# Prior version 37
|
689
|
+
return(old_infra_data_update(oConfig, '0.0.36', infra_dir))
|
690
|
+
elsif Gem::Version.new(forj_infra_version) < Gem::Version.new(INFRA_VERSION)
|
691
|
+
return(old_infra_data_update(oConfig, forj_infra_version, infra_dir))
|
692
|
+
end
|
693
|
+
end
|
644
694
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
PrcLib.message("The private key file attached to keypair named '%s' is not found. Running ssh-keygen to create it." % keys[:keypair_name])
|
653
|
-
if not File.exists?(private_key_file)
|
654
|
-
AppInit.ensure_dir_exists(File.dirname(private_key_file))
|
655
|
-
command = 'ssh-keygen -t rsa -f %s' % private_key_file
|
656
|
-
PrcLib.debug("Executing '%s'" % command)
|
657
|
-
system(command)
|
658
|
-
end
|
659
|
-
if not File.exists?(private_key_file)
|
660
|
-
PrcLib.fatal(1, "'%s' not found. Unable to add your keypair to hpcloud. Create it yourself and provide it with -p option. Then retry." % [private_key_file])
|
661
|
-
else
|
662
|
-
PrcLib.fatal(1, "ssh-keygen did not created your key pairs. Aborting. Please review errors in ~/.forj/forj.log")
|
663
|
-
end
|
664
|
-
end
|
695
|
+
def update_build_env(b_update, tag, y_dns, m_obj)
|
696
|
+
if !b_update.nil? && b_update
|
697
|
+
PrcLib.debug("Saved: '%s' = '%s'", m_obj[1], m_obj[2])
|
698
|
+
y_dns.rh_set(m_obj[2], tag)
|
699
|
+
end
|
700
|
+
b_update
|
701
|
+
end
|
665
702
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
703
|
+
def update_build_env?(b_update, tag, y_dns, m_obj)
|
704
|
+
if tag && m_obj[2]
|
705
|
+
if b_update.nil? &&
|
706
|
+
y_dns.rh_get(tag) && y_dns.rh_get(tag) != m_obj[2]
|
707
|
+
PrcLib.message('Your account setup is different than'\
|
708
|
+
' build env.')
|
709
|
+
PrcLib.message('We suggest you to update your account'\
|
710
|
+
' setup with data from your build env.')
|
711
|
+
b_update = agree('Do you want to update your setup with'\
|
712
|
+
' those build environment data?')
|
671
713
|
end
|
714
|
+
b_update = update_build_env(b_update, tag, y_dns, m_obj)
|
715
|
+
end
|
716
|
+
b_update
|
717
|
+
end
|
672
718
|
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
if
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
PrcLib.info("Private key keypair up to date.")
|
694
|
-
end
|
695
|
-
if Digest::MD5.file(public_key_file).hexdigest != Digest::MD5.file(forj_public_key_file).hexdigest
|
696
|
-
PrcLib.info("Updating public key keypair piece to FORJ keypairs list.")
|
697
|
-
FileUtils.copy(public_key_file, forj_public_key_file)
|
698
|
-
else
|
699
|
-
PrcLib.info("Public key keypair up to date.")
|
700
|
-
end
|
701
|
-
end
|
702
|
-
end
|
703
|
-
# Saving internal copy of private key file for forj use.
|
704
|
-
config.set(:keypair_path, forj_private_key_file )
|
705
|
-
PrcLib.info("Configured forj keypair '%s' with '%s'" % [ keys[:keypair_name], File.join(keys[:keypair_path], keys[:key_basename]) ] )
|
706
|
-
true # forj_setup_keypairs_files successfull
|
707
|
-
end
|
708
|
-
|
709
|
-
def forj_DNS_settings()
|
710
|
-
sAsk = "Optionally, you can ask Maestro to use/manage a domain name on your cloud. It requires your DNS cloud service to be enabled.\nDo you want to configure it?"
|
711
|
-
config.set(:dns_settings, agree(sAsk))
|
712
|
-
true
|
713
|
-
end
|
714
|
-
|
715
|
-
def forj_DNS_settings?(sKey)
|
716
|
-
# Return true to ask the question. false otherwise
|
717
|
-
if not config.get(:dns_settings)
|
718
|
-
config.set(sKey, nil)
|
719
|
-
return false # Do not ask
|
720
|
-
end
|
721
|
-
true
|
722
|
-
end
|
719
|
+
def open_build_env(build_env, tags, y_dns)
|
720
|
+
b_update = nil
|
721
|
+
|
722
|
+
File.open(build_env) do |f|
|
723
|
+
line = f.readline
|
724
|
+
next if line.match(/^(SET_[A-Z_]+)=["'](.*)["'].*$/).nil?
|
725
|
+
# f.each_line do |line|
|
726
|
+
m_obj = line.match(/^(SET_[A-Z_]+)=["'](.*)["'].*$/)
|
727
|
+
# if m_obj
|
728
|
+
PrcLib.debug("Reviewing detected '%s' tag", m_obj[1])
|
729
|
+
tag = (tags[m_obj[1]] ? tags[m_obj[1]] : nil)
|
730
|
+
b_update = update_build_env(b_update, tag, y_dns, m_obj)
|
731
|
+
# end
|
732
|
+
# end
|
733
|
+
end
|
734
|
+
rescue => e
|
735
|
+
PrcLib.fatal(1, "Failed to open the build environment file '%s'",
|
736
|
+
build_env, e)
|
737
|
+
end
|
738
|
+
end
|
723
739
|
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
740
|
+
# Functions for boot - create_or_use_infra
|
741
|
+
class ForjCoreProcess
|
742
|
+
def old_infra_data_update(oConfig, version, infra_dir)
|
743
|
+
PrcLib.info('Migrating your local infra repo (%s) to the latest version.',
|
744
|
+
version)
|
745
|
+
# Be default migration is successful. No need to rebuild it.
|
746
|
+
b_rebuild = false
|
747
|
+
case version
|
748
|
+
when '0.0.36'
|
749
|
+
# Moving from 0.0.36 or less to 0.0.37 or higher.
|
750
|
+
# SET_COMPUTE="{SET_COMPUTE!}" => Setting for Compute.
|
751
|
+
# ignored. Coming from HPC
|
752
|
+
# SET_TENANT_NAME="{SET_TENANT_NAME!}" => Setting for Compute.
|
753
|
+
# ignored. Need to query HPC from current Tenant ID
|
754
|
+
|
755
|
+
# SET_DNS_TENANTID="{SET_DNS_TENANTID!}" => Setting for DNS.
|
756
|
+
# meta = dns_tenantid
|
757
|
+
# ==> :forj_accounts, s_account_name, :dns, :tenant_id
|
758
|
+
|
759
|
+
# SET_DNS_ZONE="{SET_DNS_ZONE!}" => Setting for DNS. meta = dns_zone
|
760
|
+
# ==> :forj_accounts, s_account_name, :dns, :service
|
761
|
+
|
762
|
+
# SET_DOMAIN="{SET_DOMAIN!}" => Setting for Maestro (required)
|
763
|
+
# and DNS if enabled.
|
764
|
+
# ==> :forj_accounts, s_account_name, :dns, :domain_name
|
765
|
+
y_dns = {}
|
766
|
+
y_dns = oConfig[:dns] if oConfig.exist?(:dns)
|
767
|
+
|
768
|
+
Dir.foreach(infra_dir) do |file|
|
769
|
+
next unless /^maestro\.box\..*\.env$/ =~ file
|
770
|
+
build_env = File.join(infra_dir, file)
|
771
|
+
PrcLib.debug("Reading data from '%s'", build_env)
|
772
|
+
tags = { 'SET_DNS_TENANTID' => :tenant_id,
|
773
|
+
'SET_DNS_ZONE' => :service,
|
774
|
+
'SET_DOMAIN' => :domain_name
|
775
|
+
}
|
776
|
+
|
777
|
+
open_build_env(build_env, tags, y_dns)
|
744
778
|
end
|
745
|
-
|
746
|
-
|
779
|
+
file_ver = File.join(infra_dir, 'forj-cli.ver')
|
780
|
+
File.write(file_ver, INFRA_VERSION)
|
781
|
+
oConfig[:dns] = y_dns
|
782
|
+
oConfig.ac_save
|
783
|
+
return b_rebuild
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
747
787
|
|
788
|
+
# Functions for boot - build_userdata
|
789
|
+
class ForjCoreProcess
|
790
|
+
def run_userdata_cmd(cmd, bootstrap, mime)
|
791
|
+
# TODO: Replace shell script call to ruby functions
|
792
|
+
if PrcLib.core_level >= 1
|
793
|
+
cmd += " >> #{PrcLib.log_file}"
|
794
|
+
else
|
795
|
+
cmd += " | tee -a #{PrcLib.log_file}"
|
796
|
+
end
|
797
|
+
fail ForjError.new, "#{bootstrap} script file is" \
|
798
|
+
' not found.' unless File.exist?(bootstrap)
|
799
|
+
PrcLib.debug("Running '%s'", cmd)
|
800
|
+
Kernel.system(cmd)
|
801
|
+
|
802
|
+
fail ForjError.new, format(
|
803
|
+
"mime file '%s' not found.",
|
804
|
+
mime
|
805
|
+
) unless File.exist?(mime)
|
806
|
+
end
|
807
|
+
|
808
|
+
def build_userdata(sObjectType, hParams)
|
809
|
+
# get the paths for maestro and infra repositories
|
810
|
+
# maestro_path = hParams[:maestro_repository].values
|
811
|
+
# infra_path = hParams[:infra_repository].values
|
812
|
+
|
813
|
+
# concatenate the paths for boothook and cloud_config files
|
814
|
+
# ~ build_dir = File.expand_path(File.join($FORJ_DATA_PATH, '.build'))
|
815
|
+
# ~ boothook = File.join(maestro_path, 'build', 'bin', 'build-tools')
|
816
|
+
# ~ cloud_config = File.join(maestro_path, 'build', 'maestro')
|
817
|
+
|
818
|
+
mime = File.join(
|
819
|
+
Forj.build_path,
|
820
|
+
format('userdata.mime.%s', rand(36**5).to_s(36))
|
821
|
+
)
|
822
|
+
|
823
|
+
meta_data = JSON.generate(hParams[:metadata, :meta_data])
|
824
|
+
|
825
|
+
build_tmpl_dir = File.expand_path(File.join(LIB_PATH, 'build_tmpl'))
|
826
|
+
|
827
|
+
PrcLib.state("Preparing user_data - file '%s'", mime)
|
828
|
+
# generate boot_*.sh
|
829
|
+
mime_cmd = "#{build_tmpl_dir}/write-mime-multipart.py"
|
830
|
+
bootstrap = "#{build_tmpl_dir}/bootstrap_build.sh"
|
831
|
+
|
832
|
+
cmd = format(
|
833
|
+
"%s '%s' '%s' '%s' '%s' '%s' '%s' '%s'",
|
834
|
+
bootstrap, # script
|
835
|
+
PrcLib.data_path, # $1 = Forj data base dir
|
836
|
+
# $2 = Maestro repository dir
|
837
|
+
hParams[:maestro_repository, :maestro_repo],
|
838
|
+
config[:bootstrap_dirs], # $3 = Bootstrap directories
|
839
|
+
config[:bootstrap_extra_dir], # $4 = Bootstrap extra directory
|
840
|
+
meta_data, # $5 = meta_data (string)
|
841
|
+
mime_cmd, # $6: mime script file to execute.
|
842
|
+
mime # $7: mime file generated.
|
843
|
+
)
|
844
|
+
|
845
|
+
run_userdata_cmd(cmd, bootstrap, mime)
|
846
|
+
|
847
|
+
begin
|
848
|
+
user_data = File.read(mime)
|
849
|
+
rescue => e
|
850
|
+
PrcLib.fatal(1, e.message)
|
851
|
+
end
|
852
|
+
if PrcLib.core_level < 5
|
853
|
+
File.delete(mime)
|
854
|
+
else
|
855
|
+
ForjLib.debug(5, "user_data temp file '%s' kept", mime)
|
856
|
+
end
|
857
|
+
|
858
|
+
config[:user_data] = user_data
|
859
|
+
|
860
|
+
o_user_data = register(hParams, sObjectType)
|
861
|
+
o_user_data[:user_data] = user_data
|
862
|
+
o_user_data[:user_data_encoded] = Base64.strict_encode64(user_data)
|
863
|
+
o_user_data[:mime] = mime
|
864
|
+
PrcLib.info("user_data prepared. File: '%s'", mime)
|
865
|
+
o_user_data
|
866
|
+
end
|
748
867
|
end
|
749
868
|
|
750
|
-
#
|
869
|
+
# Functions for setup
|
751
870
|
class ForjCoreProcess
|
752
|
-
def
|
753
|
-
|
754
|
-
|
755
|
-
|
871
|
+
def create_directory(base_dir)
|
872
|
+
# unless File.directory?(base_dir)
|
873
|
+
return true if FIle.directory?(base_dir)
|
874
|
+
if agree(
|
875
|
+
format("'%s' doesn't exist. Do you want to create it?", base_dir)
|
876
|
+
)
|
877
|
+
PrcLib.ensure_dir_exists(base_dir)
|
878
|
+
# true
|
879
|
+
else
|
880
|
+
return false
|
881
|
+
end
|
882
|
+
# end
|
883
|
+
end
|
884
|
+
# Check files existence
|
885
|
+
def forj_check_keypairs_files(keypath)
|
886
|
+
key_name = config.get(:keypair_name)
|
887
|
+
|
888
|
+
keys_entered = keypair_detect(key_name, keypath)
|
889
|
+
if !keys_entered[:private_key_exist?] && !keys_entered[:public_key_exist?]
|
890
|
+
if agree('The key you entered was not found. Do you want to create' \
|
891
|
+
' this one?')
|
892
|
+
base_dir = keys_entered[:keypair_path]
|
893
|
+
return create_directory(base_dir)
|
894
|
+
else
|
895
|
+
return false
|
896
|
+
end
|
897
|
+
end
|
898
|
+
true
|
899
|
+
end
|
756
900
|
|
757
|
-
|
901
|
+
def duplicate_keyname?(keys_imported, keys, key_name)
|
902
|
+
if keys_imported && keys_imported[:key_basename] != keys[:key_basename] &&
|
903
|
+
Forj.keypairs_path != keys[:keypair_path]
|
904
|
+
PrcLib.warning("The private key '%s' was assigned to a different private"\
|
905
|
+
" key file '%s'.\nTo not overwrite it, we recommend you"\
|
906
|
+
' to choose a different keypair name.',
|
907
|
+
keys, keys_imported[:key_basename])
|
908
|
+
new_key_name = key_name
|
909
|
+
s_msg = 'Please, provide a different keypair name:'
|
910
|
+
while key_name == new_key_name
|
911
|
+
new_key_name = ask(s_msg) do |q|
|
912
|
+
q.validate = /.+/
|
913
|
+
end
|
914
|
+
new_key_name = new_key_name.to_s
|
915
|
+
s_msg = 'Incorrect. You have to choose a keypair name different' \
|
916
|
+
" than '#{key_name}'. If you want to interrupt, press Ctrl-C and" \
|
917
|
+
' retry later.\nSo, please, provide a different keypair' \
|
918
|
+
' name:' if key_name == new_key_name
|
919
|
+
end
|
920
|
+
key_name = new_key_name
|
921
|
+
config.set(:key_name, key_name)
|
922
|
+
keys = keypair_detect(key_name, key_path)
|
923
|
+
end
|
924
|
+
keys
|
925
|
+
end
|
758
926
|
|
759
|
-
|
927
|
+
def create_keys_automatically(keys, private_key_file)
|
928
|
+
return if keys[:private_key_exist?]
|
929
|
+
# Need to create a key. ask if we need so.
|
930
|
+
PrcLib.message("The private key file attached to keypair named '%s' is not"\
|
931
|
+
' found. Running ssh-keygen to create it.',
|
932
|
+
keys[:keypair_name])
|
933
|
+
unless File.exist?(private_key_file)
|
934
|
+
PrcLib.ensure_dir_exists(File.dirname(private_key_file))
|
935
|
+
command = format('ssh-keygen -t rsa -f %s', private_key_file)
|
936
|
+
PrcLib.debug(format("Executing '%s'", command))
|
937
|
+
system(command)
|
938
|
+
end
|
939
|
+
if !File.exist?(private_key_file)
|
940
|
+
PrcLib.fatal(1, "'%s' not found. Unable to add your keypair to hpcloud."\
|
941
|
+
' Create it yourself and provide it with -p option. '\
|
942
|
+
'Then retry.', private_key_file)
|
943
|
+
else
|
944
|
+
PrcLib.fatal(1, 'ssh-keygen did not created your key pairs. Aborting.'\
|
945
|
+
' Please review errors in ~/.forj/forj.log')
|
946
|
+
end
|
947
|
+
end
|
948
|
+
end
|
760
949
|
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
950
|
+
# Functions for setup
|
951
|
+
class ForjCoreProcess
|
952
|
+
def load_key_with_passphrase(keys, public_key_file, private_key_file)
|
953
|
+
# unless keys[:public_key_exist?]
|
954
|
+
return if keys[:private_key_exist?]
|
955
|
+
PrcLib.message("Your public key '%s' was not found. Getting it from the" \
|
956
|
+
' private one. It may require your passphrase.',
|
957
|
+
public_key_file)
|
958
|
+
command = format(
|
959
|
+
'ssh-keygen -y -f %s > %s',
|
960
|
+
private_key_file,
|
961
|
+
public_key_file
|
962
|
+
)
|
963
|
+
PrcLib.debug("Executing '%s'", command)
|
964
|
+
system(command)
|
965
|
+
# end
|
966
|
+
end
|
967
|
+
|
968
|
+
def save_sequences(private_key_file, forj_private_key_file,
|
969
|
+
public_key_file, forj_public_key_file, key_name
|
970
|
+
)
|
971
|
+
PrcLib.info('Importing key pair to FORJ keypairs list.')
|
972
|
+
FileUtils.copy(private_key_file, forj_private_key_file)
|
973
|
+
FileUtils.copy(public_key_file, forj_public_key_file)
|
974
|
+
# Attaching this keypair to the account
|
975
|
+
@hAccountData.rh_set(key_name, :credentials, 'keypair_name')
|
976
|
+
@hAccountData.rh_set(forj_private_key_file, :credentials, 'keypair_path')
|
977
|
+
config.local_set(key_name.to_s, private_key_file, :imported_keys)
|
978
|
+
end
|
766
979
|
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
980
|
+
def save_md5(private_key_file, forj_private_key_file,
|
981
|
+
public_key_file, forj_public_key_file
|
982
|
+
)
|
983
|
+
# Checking source/dest files content
|
984
|
+
if Digest::MD5.file(private_key_file).hexdigest !=
|
985
|
+
Digest::MD5.file(forj_private_key_file).hexdigest
|
986
|
+
PrcLib.info(
|
987
|
+
'Updating private key keypair piece to FORJ keypairs list.'
|
988
|
+
)
|
989
|
+
FileUtils.copy(private_key_file, forj_private_key_file)
|
990
|
+
else
|
991
|
+
PrcLib.info('Private key keypair up to date.')
|
992
|
+
end
|
993
|
+
if Digest::MD5.file(public_key_file).hexdigest !=
|
994
|
+
Digest::MD5.file(forj_public_key_file).hexdigest
|
995
|
+
PrcLib.info(
|
996
|
+
'Updating public key keypair piece to FORJ keypairs list.'
|
997
|
+
)
|
998
|
+
FileUtils.copy(public_key_file, forj_public_key_file)
|
999
|
+
else
|
1000
|
+
PrcLib.info('Public key keypair up to date.')
|
1001
|
+
end
|
771
1002
|
end
|
772
1003
|
end
|
773
1004
|
|
774
|
-
#
|
1005
|
+
# Functions for setup
|
775
1006
|
class ForjCoreProcess
|
776
|
-
|
1007
|
+
def save_internal_key(forj_private_key_file, keys)
|
1008
|
+
# Saving internal copy of private key file for forj use.
|
1009
|
+
config.set(:keypair_path, forj_private_key_file)
|
1010
|
+
PrcLib.info("Configured forj keypair '%s' with '%s'",
|
1011
|
+
keys[:keypair_name],
|
1012
|
+
File.join(keys[:keypair_path], keys[:key_basename])
|
1013
|
+
)
|
1014
|
+
end
|
777
1015
|
|
778
|
-
|
1016
|
+
# keypair_files post setup
|
1017
|
+
def forj_setup_keypairs_files
|
1018
|
+
# Getting Account keypair information
|
1019
|
+
key_name = config[:keypair_name]
|
1020
|
+
key_path = File.expand_path(config[:keypair_files])
|
779
1021
|
|
780
|
-
|
1022
|
+
keys_imported = nil
|
1023
|
+
keys_imported = keypair_detect(
|
1024
|
+
key_name,
|
1025
|
+
config.local_get(key_name, :imported_keys)
|
1026
|
+
) if config.local_exist?(key_name, :imported_keys)
|
1027
|
+
keys = keypair_detect(key_name, key_path)
|
781
1028
|
|
782
|
-
|
1029
|
+
keys = duplicate_keyname?(keys_imported, keys, key_name)
|
783
1030
|
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
1031
|
+
private_key_file = File.join(keys[:keypair_path], keys[:private_key_name])
|
1032
|
+
public_key_file = File.join(keys[:keypair_path], keys[:public_key_name])
|
1033
|
+
|
1034
|
+
# Creation sequences
|
1035
|
+
create_keys_automatically(keys, private_key_file)
|
1036
|
+
|
1037
|
+
load_key_with_passphrase(keys, public_key_file, private_key_file)
|
1038
|
+
|
1039
|
+
forj_private_key_file = File.join(Forj.keypairs_path, key_name)
|
1040
|
+
# forj_public_key_file = File.join($FORJ_KEYPAIRS_PATH, key_name + '.pub')
|
1041
|
+
|
1042
|
+
# Saving sequences
|
1043
|
+
if keys[:keypair_path] != Forj.keypairs_path
|
1044
|
+
if !File.exist?(forj_private_key_file) ||
|
1045
|
+
!File.exist?(forj_public_key_file)
|
1046
|
+
save_sequences(private_key_file, forj_private_key_file,
|
1047
|
+
public_key_file, forj_public_key_file, key_name
|
1048
|
+
)
|
792
1049
|
else
|
793
|
-
|
1050
|
+
save_md5(private_key_file, forj_private_key_file,
|
1051
|
+
public_key_file, forj_public_key_file
|
1052
|
+
)
|
794
1053
|
end
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
save_internal_key(forj_private_key_file, keys)
|
1057
|
+
true # forj_setup_keypairs_files successfull
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def forj_dns_settings
|
1061
|
+
s_ask = 'Optionally, you can ask Maestro to use/manage a domain name on' \
|
1062
|
+
" your cloud. It requires your DNS cloud service to be enabled.\nDo " \
|
1063
|
+
' you want to configure it?'
|
1064
|
+
config.set(:dns_settings, agree(s_ask))
|
1065
|
+
true
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
def forj_dns_settings?(sKey)
|
1069
|
+
# Return true to ask the question. false otherwise
|
1070
|
+
unless config.get(:dns_settings)
|
1071
|
+
config.set(sKey, nil)
|
1072
|
+
return false # Do not ask
|
1073
|
+
end
|
1074
|
+
true
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
def setup_tenant_name
|
1078
|
+
# TODO: To re-introduce with a Controller call instead.
|
1079
|
+
o_ssl_error = SSLErrorMgt.new # Retry object
|
1080
|
+
PrcLib.debug('Getting tenants from hpcloud cli libraries')
|
1081
|
+
begin
|
1082
|
+
tenants = Connection.instance.tenants(@sAccountName)
|
1083
|
+
rescue => e
|
1084
|
+
retry unless o_ssl_error.ErrorDetected(e.message, e.backtrace, e)
|
1085
|
+
PrcLib.fatal(1, 'Network: Unable to connect.')
|
1086
|
+
end
|
1087
|
+
tenant_id = @oConfig.ExtraGet(:hpc_accounts, @sAccountName,
|
1088
|
+
:credentials).rh_get(:tenant_id)
|
1089
|
+
tenant_name = nil
|
1090
|
+
tenants.each do |elem|
|
1091
|
+
tenant_name = elem['name'] if elem['id'] == tenant_id
|
1092
|
+
end
|
1093
|
+
if tenant_name
|
1094
|
+
PrcLib.debug("Tenant ID '%s': '%s' found.", tenant_id, tenant_name)
|
1095
|
+
@hAccountData.rh_set(tenant_name, :maestro, :tenant_name)
|
1096
|
+
else
|
1097
|
+
PrcLib.error("Unable to find the tenant Name for '%s' ID.", tenant_id)
|
1098
|
+
end
|
1099
|
+
@oConfig.set('tenants', tenants)
|
795
1100
|
end
|
796
1101
|
end
|
797
1102
|
|
798
|
-
#
|
1103
|
+
# Funtions for get
|
799
1104
|
class ForjCoreProcess
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
1105
|
+
def get_forge(sCloudObj, sForgeId, _hParams)
|
1106
|
+
s_query = {}
|
1107
|
+
h_servers = []
|
1108
|
+
s_query[:name] = sForgeId
|
1109
|
+
|
1110
|
+
o_servers = process_query(:server, s_query)
|
1111
|
+
|
1112
|
+
regex = Regexp.new(format('\.%s$', sForgeId))
|
1113
|
+
|
1114
|
+
o_servers.each do |o_server|
|
1115
|
+
o_name = o_server[:name]
|
1116
|
+
h_servers << o_server if regex =~ o_name
|
1117
|
+
end
|
1118
|
+
PrcLib.info('%s server(s) were found under instance name %s ',
|
1119
|
+
h_servers.count, s_query[:name])
|
1120
|
+
|
1121
|
+
o_forge = register(h_servers, sCloudObj)
|
1122
|
+
o_forge[:servers] = h_servers
|
1123
|
+
o_forge[:name] = sForgeId
|
1124
|
+
o_forge
|
1125
|
+
end
|
1126
|
+
end
|
809
1127
|
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
1128
|
+
# Funtions for destroy
|
1129
|
+
class ForjCoreProcess
|
1130
|
+
def delete_forge(_sCloudObj, hParams)
|
1131
|
+
PrcLib.state('Destroying server(s) of your forge')
|
1132
|
+
|
1133
|
+
forge_serverid = config.get(:forge_server)
|
1134
|
+
|
1135
|
+
o_forge = hParams[:forge]
|
1136
|
+
|
1137
|
+
o_forge[:servers].each do|server|
|
1138
|
+
next if forge_serverid && forge_serverid != server[:id]
|
1139
|
+
register(server)
|
1140
|
+
PrcLib.state("Destroying server '%s'", server[:name])
|
1141
|
+
process_delete(:server)
|
1142
|
+
end
|
1143
|
+
if forge_serverid.nil?
|
1144
|
+
PrcLib.high_level_msg("The forge '%s' has been destroyed. (all servers" \
|
1145
|
+
" linked to the forge)\n", o_forge[:name])
|
1146
|
+
else
|
1147
|
+
PrcLib.high_level_msg("Server(s) selected in the forge '%s' has been"\
|
1148
|
+
" removed.\n", o_forge[:name])
|
1149
|
+
end
|
1150
|
+
end
|
1151
|
+
end
|
814
1152
|
|
815
|
-
|
816
|
-
|
1153
|
+
# Functions for ssh
|
1154
|
+
class ForjCoreProcess
|
1155
|
+
def ssh_connection(sObjectType, hParams)
|
1156
|
+
o_forge = hParams[:forge]
|
1157
|
+
o_server = nil
|
817
1158
|
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
1159
|
+
o_forge[:servers].each do|server|
|
1160
|
+
next if hParams[:forge_server] != server[:id]
|
1161
|
+
o_server = server
|
1162
|
+
break
|
1163
|
+
end
|
823
1164
|
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
end
|
1165
|
+
# Get server information
|
1166
|
+
PrcLib.state('Getting server information')
|
1167
|
+
o_server = process_get(:server, o_server[:id])
|
1168
|
+
register(o_server)
|
829
1169
|
|
830
|
-
|
831
|
-
public_key_file = File.join(hKeys[:keypair_path], hKeys[:public_key_name])
|
1170
|
+
public_ip = ssh_server_public_ip(o_server)
|
832
1171
|
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
PrcLib.warning("Openssh public key file '%s' not found. Unable to verify keys coherence with remote server." % public_key_file)
|
838
|
-
end
|
1172
|
+
ssh_options = ssh_keypair(o_server)
|
1173
|
+
# Get ssh user
|
1174
|
+
image = process_get(:image, o_server[:image_id])
|
1175
|
+
user = hParams[:ssh_user]
|
839
1176
|
|
840
|
-
|
841
|
-
ssh_options = { :keys => private_key_file}
|
842
|
-
PrcLib.debug("Using private key '%s'." % private_key_file)
|
843
|
-
else
|
844
|
-
PrcLib.fatal 1, <<-END
|
845
|
-
The server '#{oServer[:name]}' has been configured with a keypair '#{oServer[:key_name]}' which is not found locally.
|
846
|
-
You won't be able to connect to that server without '#{oServer[:key_name]}' private key.
|
847
|
-
To connect to this box, you need to provide the appropriate private key file with option -i
|
848
|
-
END
|
849
|
-
end
|
1177
|
+
user = image[:ssh_user] if user.nil?
|
850
1178
|
|
851
|
-
|
852
|
-
image = Get(:image, oServer[:image_id])
|
853
|
-
user = hParams[:ssh_user]
|
1179
|
+
PrcLib.debug("Using account '%s'.", user)
|
854
1180
|
|
855
|
-
|
856
|
-
|
1181
|
+
begin
|
1182
|
+
PrcLib.state("creating ssh connection with '%s' box", o_server[:name])
|
1183
|
+
session = Net::SSH.start(public_ip, user, ssh_options) do |_ssh|
|
1184
|
+
ssh_login(ssh_options, user, public_ip)
|
857
1185
|
end
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
PrcLib.state("creating ssh connection with '%s' box" % oServer[:name])
|
863
|
-
session = Net::SSH.start(public_ip, user, ssh_options) do |ssh|
|
864
|
-
ssh_login(ssh_options, user, public_ip)
|
865
|
-
end
|
866
|
-
PrcLib.debug("Error closing ssh connection, box %s " % oServer[:name]) if not session
|
867
|
-
rescue => e
|
868
|
-
PrcLib.fatal 1, <<-END
|
1186
|
+
PrcLib.debug('Error closing ssh connection, box %s ',
|
1187
|
+
o_server[:name]) unless session
|
1188
|
+
rescue => e
|
1189
|
+
PrcLib.fatal 1, <<-END
|
869
1190
|
#{e.message}
|
870
|
-
You were not able to connect to this box. Please note that there is no
|
1191
|
+
You were not able to connect to this box. Please note that there is no
|
1192
|
+
garantuee that your local private key file '#{ssh_options[:keys]}' is the
|
1193
|
+
one that was used while building this box.
|
871
1194
|
You have to check with the user who created that box.
|
872
1195
|
END
|
1196
|
+
end
|
1197
|
+
register({ :success => true }, sObjectType)
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
def ssh_keypair(o_server)
|
1201
|
+
if config[:identity].nil? || !config[:identity].is_a?(String)
|
1202
|
+
h_keys = keypair_detect(
|
1203
|
+
o_server[:key_name],
|
1204
|
+
File.join(Forj.keypairs_path, o_server[:key_name])
|
1205
|
+
)
|
1206
|
+
else
|
1207
|
+
h_keys = keypair_detect(
|
1208
|
+
o_server[:key_name],
|
1209
|
+
File.expand_path(config[:identity])
|
1210
|
+
)
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
private_key_file = File.join(
|
1214
|
+
h_keys[:keypair_path],
|
1215
|
+
h_keys[:private_key_name]
|
1216
|
+
)
|
1217
|
+
public_key_file = File.join(h_keys[:keypair_path], h_keys[:public_key_name])
|
1218
|
+
|
1219
|
+
PrcLib.info("Found openssh private key file '%s'.",
|
1220
|
+
private_key_file) if h_keys[:private_key_exist?]
|
1221
|
+
|
1222
|
+
if h_keys[:public_key_exist?]
|
1223
|
+
PrcLib.info("Found openssh public key file '%s'.", public_key_file)
|
1224
|
+
else
|
1225
|
+
PrcLib.warning("Openssh public key file '%s' not found. Unable to verify"\
|
1226
|
+
' keys coherence with remote server.', public_key_file)
|
1227
|
+
end
|
1228
|
+
ssh_options = ssh_options(h_keys, private_key_file, o_server)
|
1229
|
+
ssh_options
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
def ssh_options(h_keys, private_key_file, o_server)
|
1233
|
+
if h_keys[:private_key_exist?]
|
1234
|
+
ssh_options = { :keys => private_key_file }
|
1235
|
+
PrcLib.debug("Using private key '%s'.", private_key_file)
|
1236
|
+
else
|
1237
|
+
PrcLib.fatal 1, <<-END
|
1238
|
+
The server '#{o_server[:name]}' has been configured with a keypair
|
1239
|
+
'#{o_server[:key_name]}' which is not found locally.
|
1240
|
+
You won't be able to connect to that server without
|
1241
|
+
'#{o_server[:key_name]}' private key.
|
1242
|
+
To connect to this box, you need to provide the appropriate private
|
1243
|
+
key file with option -i
|
1244
|
+
END
|
1245
|
+
end
|
1246
|
+
ssh_options
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
def ssh_server_public_ip(o_server)
|
1250
|
+
# Get Public IP of the server. Needs the server to be loaded.
|
1251
|
+
o_address = process_query(:public_ip, :server_id => o_server[:id])
|
1252
|
+
|
1253
|
+
if o_address.length == 0
|
1254
|
+
PrcLib.fatal(1, 'ip address for %s server was not found', o_server[:name])
|
1255
|
+
else
|
1256
|
+
public_ip = o_address[0][:public_ip]
|
1257
|
+
end
|
1258
|
+
public_ip
|
1259
|
+
end
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
# Functions for ssh
|
1263
|
+
class ForjCoreProcess
|
1264
|
+
def setup_ssh_user(_sCloudObj, hParams)
|
1265
|
+
images = process_query(:image, :name => hParams[:image_name])
|
1266
|
+
case images.length
|
1267
|
+
when 0
|
1268
|
+
s_default = hParams[:default_value]
|
1269
|
+
else
|
1270
|
+
if images[0, :ssh_user].nil?
|
1271
|
+
s_default = hParams[:default_value]
|
1272
|
+
else
|
1273
|
+
s_default = images[0, :ssh_user]
|
873
1274
|
end
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
def setup_ssh_user(sCloudObj, hParams)
|
878
|
-
images = Query(:image, { name: hParams[:image_name]} )
|
879
|
-
case images.length
|
880
|
-
when 0
|
881
|
-
sDefault = hParams[:default_value]
|
882
|
-
else
|
883
|
-
if images[0, :ssh_user].nil?
|
884
|
-
sDefault = hParams[:default_value]
|
885
|
-
else
|
886
|
-
sDefault = images[0, :ssh_user]
|
887
|
-
end
|
888
|
-
end
|
889
|
-
{ default_value: sDefault, list: config[:users] }
|
890
|
-
end
|
891
|
-
|
892
|
-
def ssh_login(options, user, public_ip)
|
893
|
-
sOpts = "-o StrictHostKeyChecking=no -o ServerAliveInterval=180"
|
894
|
-
sOpts += " -i %s" % options[:keys] if options[:keys]
|
895
|
-
|
896
|
-
command = 'ssh %s %s@%s' % [sOpts, user, public_ip]
|
897
|
-
PrcLib.debug("Running '%s'" % command)
|
898
|
-
system(command)
|
899
|
-
end
|
1275
|
+
end
|
1276
|
+
{ :default_value => s_default, :list => config[:users] }
|
1277
|
+
end
|
900
1278
|
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
return "ubuntu"
|
905
|
-
end
|
1279
|
+
def ssh_login(options, user, public_ip)
|
1280
|
+
s_opts = '-o StrictHostKeyChecking=no -o ServerAliveInterval=180'
|
1281
|
+
s_opts += format(' -i %s', options[:keys]) if options[:keys]
|
906
1282
|
|
1283
|
+
command = format('ssh %s %s@%s', s_opts, user, public_ip)
|
1284
|
+
PrcLib.debug("Running '%s'", command)
|
1285
|
+
system(command)
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
def ssh_user(image_name)
|
1289
|
+
return 'fedora' if image_name =~ /fedora/i
|
1290
|
+
return 'centos' if image_name =~ /centos/i
|
1291
|
+
'ubuntu'
|
1292
|
+
end
|
907
1293
|
end
|