forj 0.0.39 → 0.0.40
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/Gemfile +11 -2
- data/README.md +30 -16
- data/Rakefile +6 -1
- data/bin/forj +113 -54
- data/lib/boot.rb +37 -36
- data/lib/connection.rb +3 -3
- data/lib/defaults.yaml +5 -3
- data/lib/forj-account.rb +454 -0
- data/lib/forj-config.rb +181 -132
- data/lib/log.rb +6 -5
- data/lib/network.rb +4 -4
- data/lib/repositories.rb +1 -1
- data/lib/security.rb +55 -26
- data/lib/setup.rb +7 -291
- data/spec/connection_spec.rb +5 -1
- data/spec/forj-config_spec.rb +121 -19
- metadata +3 -2
data/lib/connection.rb
CHANGED
@@ -39,7 +39,7 @@ class ForjConnection
|
|
39
39
|
@oConfig = oConfig
|
40
40
|
@sAccountName = @oConfig.get('account_name')
|
41
41
|
@provider='HP' # TODO: Support multiple provider. (Generic Provider object required)
|
42
|
-
@sAccountName = @oConfig.get(
|
42
|
+
@sAccountName = @oConfig.get(:provider) if not @sAccountName
|
43
43
|
@sAccountName = 'hpcloud' if not @sAccountName
|
44
44
|
|
45
45
|
@credentials = get_credentials()
|
@@ -71,7 +71,7 @@ class ForjConnection
|
|
71
71
|
if not oSSLError.ErrorDetected(e.message,e.backtrace)
|
72
72
|
retry
|
73
73
|
end
|
74
|
-
Logging.fatal(1, 'Compute: Unable to connect.')
|
74
|
+
Logging.fatal(1, 'Compute: Unable to connect.', e)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -91,7 +91,7 @@ class ForjConnection
|
|
91
91
|
if not oSSLError.ErrorDetected(e.message,e.backtrace)
|
92
92
|
retry
|
93
93
|
end
|
94
|
-
Logging.fatal(1, 'Network: Unable to connect.')
|
94
|
+
Logging.fatal(1, 'Network: Unable to connect.', e)
|
95
95
|
end
|
96
96
|
|
97
97
|
end
|
data/lib/defaults.yaml
CHANGED
@@ -22,11 +22,13 @@ default:
|
|
22
22
|
image: Ubuntu Precise 12.04.4 LTS Server 64-bit 20140414 (Rescue Image)
|
23
23
|
|
24
24
|
# Flavor to use for Maestro
|
25
|
-
flavor: standard.
|
25
|
+
flavor: standard.medium
|
26
|
+
# Default flavor to use for all Blueprint nodes.
|
27
|
+
bp_flavor: standard.small
|
26
28
|
|
27
29
|
# Ports to open for Maestro, added to the security group
|
28
30
|
security_group: forj
|
29
|
-
ports: [22, 80, 443, 3000, 3131
|
31
|
+
ports: [22, 80, 443, 3000, 3131-3135, 4505-4506, 5000, 5666, 8000, 8080-8081, 8083, 8125, 8139-8140, 8773-8776, 9292, 29418, 35357]
|
30
32
|
|
31
33
|
# Private key file path. Those files (private/public key) will be added to ~/.forj/keypairs/ as respectively 'keypair_name' and 'keypair_name'.pub
|
32
34
|
keypair_path: ~/.ssh/forj-id_rsa
|
@@ -39,7 +41,7 @@ default:
|
|
39
41
|
build_config: box
|
40
42
|
branch: master
|
41
43
|
box_name: maestro
|
42
|
-
description:
|
44
|
+
:description:
|
43
45
|
# Description of build.sh environment variable defined by forj cli for build.sh. (~/.forj/infra/build/<Account>.build.env)
|
44
46
|
FORJ_HPC: "HPCloud cli Account used to build your Maestro box"
|
45
47
|
FORJ_HPC_COMPUTE: "HPCloud Compute service (like region-b.geo-1) used to run your Maestro Box"
|
data/lib/forj-account.rb
ADDED
@@ -0,0 +1,454 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'highline/import'
|
20
|
+
|
21
|
+
require 'yaml_parse.rb'
|
22
|
+
include YamlParse
|
23
|
+
require 'helpers.rb'
|
24
|
+
include Helpers
|
25
|
+
|
26
|
+
require 'encryptor' # gem install encryptor
|
27
|
+
require 'base64'
|
28
|
+
|
29
|
+
# TODO: To move to a specific module driven by providers.
|
30
|
+
require 'hpcloud/version'
|
31
|
+
require 'hpcloud/config'
|
32
|
+
require 'hpcloud/accounts'
|
33
|
+
require 'hpcloud/connection'
|
34
|
+
include HP::Cloud
|
35
|
+
|
36
|
+
class ForjAccount
|
37
|
+
|
38
|
+
attr_reader :sAccountName
|
39
|
+
attr_reader :hAccountData
|
40
|
+
|
41
|
+
# This object manage data located in oConfig[:hpc_accounts/AccountName]
|
42
|
+
|
43
|
+
def initialize(oConfig)
|
44
|
+
# Initialize object
|
45
|
+
@oConfig = oConfig
|
46
|
+
|
47
|
+
if @oConfig.get('account_name')
|
48
|
+
@sAccountName = @oConfig.get('account_name')
|
49
|
+
else
|
50
|
+
@sAccountName = 'hpcloud'
|
51
|
+
end
|
52
|
+
@sAccountFile = File.join($FORJ_ACCOUNTS_PATH, @sAccountName)
|
53
|
+
|
54
|
+
sProvider = 'hpcloud'
|
55
|
+
sProvider = @oConfig.get(:provider) if @oConfig.get(:provider)
|
56
|
+
|
57
|
+
@hAccountData = {}
|
58
|
+
rhSet(@hAccountData, @sAccountName, [:account, :name]) if rhExist?(@hAccountData, [:account, :name]) != 2
|
59
|
+
rhSet(@hAccountData, sProvider, [:account, :provider]) if rhExist?(@hAccountData, [:account, :provider]) != 2
|
60
|
+
end
|
61
|
+
|
62
|
+
def get(section, key, default = nil)
|
63
|
+
@oConfig.get(key, rhGet(@hAccountData, section), default )
|
64
|
+
end
|
65
|
+
|
66
|
+
def ac_load(sAccountName = @sAccountName)
|
67
|
+
# Load Account Information
|
68
|
+
|
69
|
+
if sAccountName != @sAccountName
|
70
|
+
@sAccountName = sAccountName
|
71
|
+
@sAccountFile = File.join($FORJ_ACCOUNTS_PATH, @sAccountName)
|
72
|
+
end
|
73
|
+
|
74
|
+
if File.exists?(@sAccountFile)
|
75
|
+
@hAccountData = @oConfig.ExtraLoad(@sAccountFile, :forj_accounts, @sAccountName)
|
76
|
+
sProvider = @oConfig.get(:provider, nil, 'hpcloud')
|
77
|
+
rhSet(@hAccountData, @sAccountName, :account, :name) if rhExist?(@hAccountData, :account, :name) != 2
|
78
|
+
rhSet(@hAccountData, sProvider, :account, :provider) if rhExist?(@hAccountData, :account, :provider) != 2
|
79
|
+
provider_load()
|
80
|
+
return @hAccountData
|
81
|
+
end
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def ac_save()
|
86
|
+
@oConfig.ExtraSet(:forj_accounts, @sAccountName, nil, @hAccountData)
|
87
|
+
@oConfig.ExtraSave(@sAccountFile, :forj_accounts, @sAccountName)
|
88
|
+
|
89
|
+
if not @oConfig.LocalDefaultExist?('account_name')
|
90
|
+
@oConfig.LocalSet('account_name',@sAccountName)
|
91
|
+
@oConfig.SaveConfig
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def setup()
|
96
|
+
# Full setup to make it work.
|
97
|
+
|
98
|
+
# setting up provider account - Required, while calling external provider tool, like hpcloud.
|
99
|
+
self.setup_provider_account()
|
100
|
+
|
101
|
+
# Implementation of simple credential encoding for build.sh/maestro
|
102
|
+
self.setup_maestro_creds()
|
103
|
+
|
104
|
+
# DNS Setting for Gardener
|
105
|
+
self.setup_dns()
|
106
|
+
|
107
|
+
# Check/create keypair
|
108
|
+
self.keypair_setup()
|
109
|
+
|
110
|
+
# Checking cloud connection
|
111
|
+
Logging.message("Checking cloud connection")
|
112
|
+
oFC = ForjConnection.new(@oConfig)
|
113
|
+
|
114
|
+
Logging.message("Setup '%s' done. Thank you." % @sAccountName)
|
115
|
+
end
|
116
|
+
|
117
|
+
def setup_provider_account()
|
118
|
+
# TODO: Support of multiple providers thanks to fog.
|
119
|
+
# TODO: Replace this code by our own forj account setup, inspired/derived from hpcloud account::setup
|
120
|
+
|
121
|
+
# delegate the initial configuration to hpcloud (unix_cli)
|
122
|
+
if File.exists?(File.join($HPC_ACCOUNTS, 'hp')) and not File.exists?(File.join($HPC_ACCOUNTS, @sAccountName)) and @sAccountName != 'hp'
|
123
|
+
Logging.info("hpcloud: Copying 'hp' account setup to '%s'" % @sAccountName)
|
124
|
+
Kernel.system('hpcloud account:copy hp %s' % [@sAccountName])
|
125
|
+
end
|
126
|
+
|
127
|
+
Logging.info("Configuring hpcloud account '%s'" % [@sAccountName] )
|
128
|
+
command = 'hpcloud account:setup %s' % [@sAccountName]
|
129
|
+
Logging.debug("Executing : '%s'" % command)
|
130
|
+
case Kernel.system(command)
|
131
|
+
when false
|
132
|
+
Logging.fatal(1, "Unable to setup your '%s' account" % [@sAccountName])
|
133
|
+
when nil
|
134
|
+
Logging.fatal(1, "Unable to execute 'hpcloud' cli. Please check hpcloud installation.")
|
135
|
+
end
|
136
|
+
|
137
|
+
provider_load() # To ensure latest provider data are loaded
|
138
|
+
|
139
|
+
setup_tenant_name()
|
140
|
+
end
|
141
|
+
|
142
|
+
def provider_load()
|
143
|
+
# TODO: Should be provider agnostic
|
144
|
+
# Loading HPCloud account setting in Config.
|
145
|
+
hpc_account_file = File.join($HPC_ACCOUNTS, @sAccountName)
|
146
|
+
|
147
|
+
# Maestro compute use openstack. It requires meta tenant_name (not ID). Need to query HPC to get the Project Name from the ID.
|
148
|
+
@oConfig.ExtraLoad(hpc_account_file, :hpc_accounts, @sAccountName)
|
149
|
+
end
|
150
|
+
|
151
|
+
def setup_tenant_name()
|
152
|
+
# Maestro uses fog/openstack to connect to the cloud. It needs Tenant name instead of tenant ID.
|
153
|
+
# Getting it from Compute connection and set it
|
154
|
+
|
155
|
+
oSSLError=SSLErrorMgt.new # Retry object
|
156
|
+
Logging.debug("Getting tenants from hpcloud cli libraries")
|
157
|
+
begin
|
158
|
+
tenants = Connection.instance.tenants(@sAccountName)
|
159
|
+
rescue => e
|
160
|
+
if not oSSLError.ErrorDetected(e.message,e.backtrace)
|
161
|
+
retry
|
162
|
+
end
|
163
|
+
Logging.fatal(1, 'Network: Unable to connect.')
|
164
|
+
end
|
165
|
+
tenant_id = rhGet(@oConfig.ExtraGet(:hpc_accounts, @sAccountName, :credentials), :tenant_id)
|
166
|
+
tenant_name = nil
|
167
|
+
tenants.each { |elem| tenant_name = elem['name'] if elem['id'] == tenant_id }
|
168
|
+
if tenant_name
|
169
|
+
Logging.debug("Tenant ID '%s': '%s' found." % [tenant_id, tenant_name])
|
170
|
+
hCompute = { :tenant_name => tenant_name }
|
171
|
+
rhSet(@hAccountData, hCompute, :compute)
|
172
|
+
else
|
173
|
+
Logging.error("Unable to find the tenant Name for '%s' ID." % tenant_id)
|
174
|
+
end
|
175
|
+
@oConfig.set('tenants', tenants)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Setting up DNS information
|
179
|
+
def setup_dns()
|
180
|
+
# Get HPCloud account definition
|
181
|
+
yHPC = @oConfig.ExtraGet(:hpc_accounts, @sAccountName)
|
182
|
+
# Get Forj account definition
|
183
|
+
yDNS = rhGet(@hAccountData, :dns)
|
184
|
+
yDNS = {} if not yDNS
|
185
|
+
|
186
|
+
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?"
|
187
|
+
if agree(sAsk)
|
188
|
+
# Getting tenants
|
189
|
+
tenants = @oConfig.get('tenants')
|
190
|
+
|
191
|
+
# Question about DNS Tenant ID
|
192
|
+
# In HPCloud : credentials/tenant_id
|
193
|
+
aDNS_TenantIDs = []
|
194
|
+
sDNS_TenantIDs = rhGet(yDNS, :tenant_id)
|
195
|
+
sDNS_TenantIDs = rhGet(yHPC, :credentials, :tenant_id) if not sDNS_TenantIDs and rhExist?(yHPC, :credentials, :tenant_id) > 0
|
196
|
+
|
197
|
+
Logging.message("Following are the list of know project attached to your credentials:")
|
198
|
+
tenants.each do | elem |
|
199
|
+
aDNS_TenantIDs.push(elem['id'])
|
200
|
+
if sDNS_TenantIDs and elem['id'] == sDNS_TenantIDs
|
201
|
+
Logging.message("%s - %s" % [ANSI.bold+elem['id']+ANSI.reset, elem['name']])
|
202
|
+
else
|
203
|
+
Logging.message("%s - %s" % [elem['id'], elem['name']])
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
sOption = ' [%s]' % aDNS_TenantIDs.join(', ') if aDNS_TenantIDs.length() == 2
|
208
|
+
sDNS_TenantID = ask('Enter DNS Tenant ID:%s' % sOption) do |q|
|
209
|
+
q.default = sDNS_TenantIDs
|
210
|
+
q.validate = /[\w\d]+/
|
211
|
+
end
|
212
|
+
yDNS[:tenant_id] = sDNS_TenantID.to_s
|
213
|
+
|
214
|
+
# Question about DNS Service
|
215
|
+
# In HPCloud : regions/dns
|
216
|
+
if sDNS_TenantID == rhGet(yHPC, :credentials, :tenant_id)
|
217
|
+
sDNS_Service = rhGet(yHPC, :regions, :dns)
|
218
|
+
else
|
219
|
+
aDNS_Services = []
|
220
|
+
aDNS_Services.push(rhGet(yDNS, :service)) if rhExist?(yDNS, :service) > 0
|
221
|
+
|
222
|
+
sDNS_Service = ask("Enter DNS Service for the Tenant ID '%s' (ex: region-a.geo-1): " % sDNS_TenantID) do |q|
|
223
|
+
q.validate = /[\w.-]+/
|
224
|
+
end
|
225
|
+
end
|
226
|
+
yDNS[:service] = sDNS_Service.to_s
|
227
|
+
|
228
|
+
else
|
229
|
+
yDNS.delete(:service)
|
230
|
+
yDNS.delete(:tenant_id)
|
231
|
+
Logging.message("Maestro won't manage any Domain with '%s' provider." % [ rhGet(@hAccountData, [:account, :provider])])
|
232
|
+
end
|
233
|
+
# Question about Domain name
|
234
|
+
previousDomainName = rhGet(yDNS, :domain_name) if rhExist?(yDNS, :domain_name) > 0
|
235
|
+
|
236
|
+
sDNS_DomainName = ask('Enter Domain name to add to hostnames (puppet requirement) (ex: dev.forj.io):') do |q|
|
237
|
+
q.default = previousDomainName if previousDomainName
|
238
|
+
q.validate = /[\w._]+/
|
239
|
+
end
|
240
|
+
yDNS[:domain_name] = sDNS_DomainName.to_s
|
241
|
+
|
242
|
+
# Attaching to the account.
|
243
|
+
rhSet(@hAccountData, yDNS, :dns)
|
244
|
+
end
|
245
|
+
|
246
|
+
# manage keypair attached to a FORJ account.
|
247
|
+
def keypair_setup()
|
248
|
+
|
249
|
+
# Getting Account keypair information
|
250
|
+
yCreds = rhGet(@hAccountData, :credentials)
|
251
|
+
key_name = @oConfig.get('keypair_name', yCreds )
|
252
|
+
orig_key_path = File.expand_path(@oConfig.get('keypair_path', yCreds))
|
253
|
+
|
254
|
+
Logging.warning("'keypair_path' is missing at least from defaults.yaml. To fix it, set it in your configuration file ~/.forj/config.yaml under default section") if not orig_key_path
|
255
|
+
key_path = nil
|
256
|
+
while not key_path
|
257
|
+
key_path = ask ("Please provide the SSH private key path used by default on this account:") do | q |
|
258
|
+
q.default = orig_key_path
|
259
|
+
q.validate = /.*+/
|
260
|
+
end
|
261
|
+
keys_entered = keypair_detect(key_name, key_path)
|
262
|
+
if not keys_entered[:private_key_exist?] and not keys_entered[:public_key_exist?]
|
263
|
+
if agree("The key you entered was not found. Do you want to create this one?")
|
264
|
+
base_dir = File.dirname(keys_entered[:keypair_path])
|
265
|
+
if File.directory?(base_dir)
|
266
|
+
if agree("'%s' doesn't exist. Do you want to create it?")
|
267
|
+
ensure_forj_dirs_exists(base_dir)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
else
|
271
|
+
key_path = nil
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
keys_imported = nil
|
276
|
+
keys_imported = keypair_detect(key_name, @oConfig.LocalGet(key_name, :imported_keys)) if @oConfig.LocalExist?(key_name, :imported_keys)
|
277
|
+
|
278
|
+
if keys_imported and keys_imported[:key_basename] != keys_entered[:key_basename] and $FORJ_KEYPAIRS_PATH != keys_entered[:keypair_path]
|
279
|
+
Logging.warning("The private key '%s' was imported from a different private key file '%s'.\nTo not overwrite it, we recommend you to choose a different keypair name." % [key_name, sImportedKey])
|
280
|
+
key_name = nil
|
281
|
+
end
|
282
|
+
|
283
|
+
key_name = ask ("Please provide the keypair name used by default on this account:") do | q |
|
284
|
+
q.default = key_name
|
285
|
+
q.validate = /.*+/
|
286
|
+
end
|
287
|
+
key_name = key_name.to_s
|
288
|
+
|
289
|
+
keys = keypair_detect(key_name, key_path)
|
290
|
+
|
291
|
+
Logging.info("Configuring forj keypair '%s'" % [ keys[:keypair_name] ] )
|
292
|
+
|
293
|
+
|
294
|
+
private_key_file = File.join(keys[:keypair_path], keys[:private_key_name])
|
295
|
+
public_key_file = File.join(keys[:keypair_path], keys[:public_key_name])
|
296
|
+
|
297
|
+
|
298
|
+
# Creation sequences
|
299
|
+
if not keys[:private_key_exist?]
|
300
|
+
# Need to create a key. ask if we need so.
|
301
|
+
Logging.message("Private key file '%s' was not found. forj will propose to create one for you. Please review the proposed private key file name and path.\nYou can press Enter to accept the default value." % keys[:private_key_path])
|
302
|
+
real_key_path = File.expand_path(ask("Private key file path:") do |q|
|
303
|
+
q.validate = /\w+/
|
304
|
+
q.default = private_key_file
|
305
|
+
end)
|
306
|
+
if not File.exists?(real_key_path)
|
307
|
+
Helpers.ensure_dir_exists(File.dirname(real_key_path))
|
308
|
+
command = 'ssh-keygen -t rsa -f %s' % real_key_path
|
309
|
+
Logging.debug("Executing '%s'" % command)
|
310
|
+
system(command)
|
311
|
+
end
|
312
|
+
if not File.exists?(real_key_path)
|
313
|
+
Logging.fatal(1, "'%s' not found. Unable to add your keypair to hpcloud. Create it yourself and provide it with -p option. Then retry." % [real_key_path])
|
314
|
+
else
|
315
|
+
if real_key_path != key_path and not @oConfig.LocalDefaultExist?('keypair_path')
|
316
|
+
Logging.debug("Saving forj keypair '%s' as default." % [real_key_path] )
|
317
|
+
@oConfig.LocalSet('keypair_path', real_key_path)
|
318
|
+
@oConfig.SaveConfig()
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
if not keys[:public_key_exist?]
|
324
|
+
Logging.message("Your public key '%s' was not found. Getting it from the private one. It may require your passphrase." % [public_key_file])
|
325
|
+
command = 'ssh-keygen -y -f %s > %s' % [private_key_file,public_key_file ]
|
326
|
+
Logging.debug("Executing '%s'" % command)
|
327
|
+
system(command)
|
328
|
+
end
|
329
|
+
|
330
|
+
forj_private_key_file = File.join($FORJ_KEYPAIRS_PATH, key_name )
|
331
|
+
forj_public_key_file = File.join($FORJ_KEYPAIRS_PATH, key_name + ".pub")
|
332
|
+
|
333
|
+
# Saving sequences
|
334
|
+
if keys[:keypair_path] != $FORJ_KEYPAIRS_PATH
|
335
|
+
if not File.exists?(forj_private_key_file)
|
336
|
+
Logging.info("Importing key pair to FORJ keypairs list.")
|
337
|
+
FileUtils.copy(private_key_file, forj_private_key_file)
|
338
|
+
FileUtils.copy(public_key_file, forj_public_key_file)
|
339
|
+
# Attaching this keypair to the account
|
340
|
+
rhSet(@hAccountData, key_name, :credentials, 'keypair_name')
|
341
|
+
rhSet(@hAccountData, forj_private_key_file, :credentials, 'keypair_path')
|
342
|
+
@oConfig.LocalSet(key_name.to_s, private_key_file, :imported_keys)
|
343
|
+
@oConfig.SaveConfig()
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def setup_maestro_creds()
|
349
|
+
# Check required global data
|
350
|
+
if not $FORJ_CREDS_PATH
|
351
|
+
Logging.fatal(1, "Internal error: '$FORJ_CREDS_PATH' missing.")
|
352
|
+
end
|
353
|
+
if not Helpers.dir_exists?($FORJ_CREDS_PATH)
|
354
|
+
Logging.fatal(1, "Internal error: '%s' doesn't exist." % $FORJ_CREDS_PATH)
|
355
|
+
end
|
356
|
+
|
357
|
+
Logging.info("Completing hpcloud account '%s' information." % [@sAccountName] )
|
358
|
+
|
359
|
+
forj_user = rhGet(@hAccountData, :credentials, :os_user)
|
360
|
+
enc_hpcloud_os_key = rhGet(@hAccountData, :credentials, :os_enckey)
|
361
|
+
|
362
|
+
hpcloud_os_user = ask('Enter hpcloud username: ') do |q|
|
363
|
+
q.validate = /\w+/
|
364
|
+
q.default = forj_user if forj_user
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
# Checking key file used to encrypt/decrypt passwords
|
369
|
+
key_file = File.join($FORJ_CREDS_PATH, '.key')
|
370
|
+
if not File.exists?(key_file)
|
371
|
+
# Need to create a random key.
|
372
|
+
entr = { :key => rand(36**10).to_s(36), :salt => Time.now.to_i.to_s, :iv => OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv}
|
373
|
+
|
374
|
+
Logging.debug("Writing '%s' key file" % key_file)
|
375
|
+
File.open(key_file, 'w') do |out|
|
376
|
+
out.write(Base64::encode64(entr.to_yaml))
|
377
|
+
end
|
378
|
+
else
|
379
|
+
Logging.debug("Loading '%s' key file" % key_file)
|
380
|
+
encoded_key = IO.read(key_file)
|
381
|
+
entr = YAML.load(Base64::decode64(encoded_key))
|
382
|
+
end
|
383
|
+
|
384
|
+
if enc_hpcloud_os_key
|
385
|
+
hpcloud_os_key_hidden = '*' * Encryptor.decrypt(
|
386
|
+
:value => Base64::strict_decode64(enc_hpcloud_os_key),
|
387
|
+
:key => entr[:key],
|
388
|
+
:iv => entr[:iv],
|
389
|
+
:salt => entr[:salt]
|
390
|
+
).length
|
391
|
+
hpcloud_os_key_hidden="[%s]" % hpcloud_os_key_hidden
|
392
|
+
Logging.message("A password is already set for '%s'. If you want to keep it, just press Enter" % [hpcloud_os_user])
|
393
|
+
else
|
394
|
+
hpcloud_os_key_hidden = ""
|
395
|
+
end
|
396
|
+
|
397
|
+
hpcloud_os_key = ""
|
398
|
+
while hpcloud_os_key == ""
|
399
|
+
# ask for password.
|
400
|
+
hpcloud_os_key = ask("Enter hpcloud password for '%s': %s" % [hpcloud_os_user, hpcloud_os_key_hidden]) do |q|
|
401
|
+
q.echo = '*'
|
402
|
+
end
|
403
|
+
if hpcloud_os_key == "" and enc_hpcloud_os_key
|
404
|
+
hpcloud_os_key = Encryptor.decrypt(:value => Base64::strict_decode64(enc_hpcloud_os_key), :key => entr[:key], :iv => entr[:iv], :salt => entr[:salt])
|
405
|
+
else
|
406
|
+
Logging.message("The password cannot be empty.") if hpcloud_os_key == ""
|
407
|
+
end
|
408
|
+
end
|
409
|
+
enc_hpcloud_os_key = Base64::strict_encode64(Encryptor.encrypt(:value => hpcloud_os_key, :key => entr[:key], :iv => entr[:iv], :salt => entr[:salt]))
|
410
|
+
|
411
|
+
cloud_fog = File.join($FORJ_CREDS_PATH, @sAccountName+'.g64')
|
412
|
+
|
413
|
+
# Security fix: Remove old temp file with clear password.
|
414
|
+
old_file = '%s/master.forj-13.5' % [$FORJ_CREDS_PATH]
|
415
|
+
File.delete(old_file) if File.exists?(old_file)
|
416
|
+
old_file = '%s/creds' % [$FORJ_CREDS_PATH]
|
417
|
+
File.delete(old_file) if File.exists?(old_file)
|
418
|
+
|
419
|
+
provider_load() if not @oConfig.ExtraExist?(:hpc_accounts, @sAccountName)
|
420
|
+
hpc_creds = @oConfig.ExtraGet(:hpc_accounts, @sAccountName, :credentials)
|
421
|
+
|
422
|
+
rhSet(@hAccountData, hpcloud_os_user.to_s, :credentials, :os_user)
|
423
|
+
rhSet(@hAccountData, enc_hpcloud_os_key, :credentials, :os_enckey)
|
424
|
+
|
425
|
+
IO.popen('gzip -c | base64 -w0 > %s' % [cloud_fog], 'r+') {|pipe|
|
426
|
+
pipe.puts('HPCLOUD_OS_USER=%s' % [hpcloud_os_user] )
|
427
|
+
pipe.puts('HPCLOUD_OS_KEY=%s' % [hpcloud_os_key] )
|
428
|
+
pipe.puts('DNS_KEY=%s' % [hpc_creds[:account_id]] )
|
429
|
+
pipe.puts('DNS_SECRET=%s' % [hpc_creds[:secret_key]])
|
430
|
+
pipe.close_write
|
431
|
+
}
|
432
|
+
Logging.info("'%s' written." % cloud_fog)
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def ensure_forj_dirs_exists()
|
437
|
+
# Function to create FORJ paths if missing.
|
438
|
+
|
439
|
+
# Defining Global variables
|
440
|
+
$FORJ_DATA_PATH = File.expand_path(File.join('~', '.forj'))
|
441
|
+
$FORJ_ACCOUNTS_PATH = File.join($FORJ_DATA_PATH, 'accounts')
|
442
|
+
$FORJ_KEYPAIRS_PATH = File.join($FORJ_DATA_PATH, 'keypairs')
|
443
|
+
$FORJ_CREDS_PATH = File.expand_path(File.join('~', '.cache', 'forj'))
|
444
|
+
|
445
|
+
# TODO: To move to an hpcloud object.
|
446
|
+
$HPC_KEYPAIRS = File.expand_path(File.join('~', '.hpcloud', 'keypairs'))
|
447
|
+
$HPC_ACCOUNTS = File.expand_path(File.join('~', '.hpcloud', 'accounts'))
|
448
|
+
|
449
|
+
Helpers.ensure_dir_exists($FORJ_DATA_PATH)
|
450
|
+
Helpers.ensure_dir_exists($FORJ_ACCOUNTS_PATH)
|
451
|
+
Helpers.ensure_dir_exists($FORJ_KEYPAIRS_PATH)
|
452
|
+
FileUtils.chmod(0700, $FORJ_KEYPAIRS_PATH)
|
453
|
+
Helpers.ensure_dir_exists($FORJ_CREDS_PATH)
|
454
|
+
end
|