forj 0.0.36 → 0.0.37
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/bin/forj +31 -32
- data/lib/boot.rb +97 -31
- data/lib/connection.rb +46 -32
- data/lib/defaults.yaml +15 -0
- data/lib/forj-config.rb +197 -65
- data/lib/repositories.rb +112 -13
- data/lib/security.rb +28 -6
- data/lib/setup.rb +228 -81
- data/lib/ssh.sh +2 -2
- metadata +5 -6
- data/lib/build_tmpl/build-env.py +0 -293
data/lib/setup.rb
CHANGED
@@ -24,59 +24,187 @@ include YamlParse
|
|
24
24
|
require_relative 'helpers.rb'
|
25
25
|
include Helpers
|
26
26
|
|
27
|
+
require 'encryptor' # gem install encryptor
|
28
|
+
require 'base64'
|
29
|
+
|
30
|
+
# TODO: To move to a specific module driven by providers.
|
31
|
+
require 'hpcloud/version'
|
32
|
+
require 'hpcloud/config'
|
33
|
+
require 'hpcloud/accounts'
|
34
|
+
require 'hpcloud/connection'
|
35
|
+
include HP::Cloud
|
36
|
+
|
27
37
|
#
|
28
38
|
# Setup module call the hpcloud functions
|
29
39
|
#
|
30
40
|
module Setup
|
31
|
-
|
32
|
-
begin
|
41
|
+
def setup(oConfig, options )
|
33
42
|
|
34
|
-
|
43
|
+
# TODO: Provide a way to re-edit all or partially elements set up by this function.
|
44
|
+
begin
|
45
|
+
Logging.fatal(1, 'No provider specified.') if not oConfig.exist?('provider')
|
35
46
|
|
36
|
-
|
37
|
-
|
47
|
+
sProvider = oConfig.get('provider')
|
48
|
+
sAccountName = sProvider # By default, the account name uses the same provider name.
|
49
|
+
sAccountName = options[:account_name] if options[:account_name]
|
38
50
|
|
39
|
-
|
40
|
-
|
41
|
-
|
51
|
+
if sProvider != 'hpcloud'
|
52
|
+
Logging.fatal(1, "forj setup support only hpcloud. '%s' is currently not supported." % sProvider)
|
53
|
+
end
|
42
54
|
|
43
|
-
|
44
|
-
|
55
|
+
# setting up provider account - Required, while calling external provider tool, like hpcloud.
|
56
|
+
setup_provider_account(oConfig, sAccountName)
|
45
57
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
58
|
+
# Implementation of simple credential encoding for build.sh/maestro
|
59
|
+
save_maestro_creds(oConfig, sAccountName)
|
60
|
+
|
61
|
+
# DNS Setting for Gardener
|
62
|
+
setup_dns(oConfig, sAccountName)
|
63
|
+
|
64
|
+
# Check/create keypair
|
65
|
+
keypair_setup(oConfig)
|
66
|
+
|
67
|
+
# Checking cloud connection
|
68
|
+
Logging.message("Checking cloud connection")
|
69
|
+
oFC=ForjConnection.new(oConfig)
|
52
70
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
when nil
|
60
|
-
Logging.fatal(1, "Unable to execute 'hpcloud' cli. Please check hpcloud installation.")
|
71
|
+
Logging.message("Setup '%s' done. Thank you." % sAccountName)
|
72
|
+
|
73
|
+
rescue RuntimeError => e
|
74
|
+
Logging.fatal(1,e.message)
|
75
|
+
rescue => e
|
76
|
+
Logging.fatal(1,"%s\n%s" % [e.message,e.backtrace.join("\n")])
|
61
77
|
end
|
78
|
+
end
|
79
|
+
end
|
62
80
|
|
63
|
-
|
64
|
-
|
65
|
-
|
81
|
+
def setup_tenant_name(oConfig, sAccountName)
|
82
|
+
# Maestro uses fog/openstack to connect to the cloud. It needs Tenant name instead of tenant ID.
|
83
|
+
# Getting it from Compute connection and set it
|
84
|
+
|
85
|
+
oSSLError=SSLErrorMgt.new # Retry object
|
86
|
+
Logging.debug("Getting tenants from hpcloud cli libraries")
|
87
|
+
begin
|
88
|
+
tenants = Connection.instance.tenants(sAccountName)
|
89
|
+
rescue => e
|
90
|
+
if not oSSLError.ErrorDetected(e.message,e.backtrace)
|
91
|
+
retry
|
66
92
|
end
|
93
|
+
Logging.fatal(1, 'Network: Unable to connect.')
|
94
|
+
end
|
95
|
+
tenant_id = rhGet(oConfig.ExtraGet(:hpc_accounts, sAccountName, :credentials), :tenant_id)
|
96
|
+
tenant_name = nil
|
97
|
+
tenants.each { |elem| tenant_name = elem['name'] if elem['id'] == tenant_id }
|
98
|
+
if tenant_name
|
99
|
+
Logging.debug("Tenant ID '%s': '%s' found." % [tenant_id, tenant_name])
|
100
|
+
hCompute = { :tenant_name => tenant_name }
|
101
|
+
oConfig.ExtraSet(:forj_accounts, sAccountName, :compute, hCompute)
|
102
|
+
else
|
103
|
+
Logging.error("Unable to found the tenant Name for '%s' ID." % tenant_id)
|
104
|
+
end
|
105
|
+
oConfig.set('tenants', tenants)
|
106
|
+
end
|
107
|
+
|
108
|
+
def setup_provider_account(oConfig, sAccountName)
|
109
|
+
# TODO: Support of multiple providers thanks to fog.
|
110
|
+
# TODO: Replace this code by our own forj account setup, inspired/derived from hpcloud account::setup
|
111
|
+
|
112
|
+
# delegate the initial configuration to hpcloud (unix_cli)
|
113
|
+
if File.exists?(File.join($HPC_ACCOUNTS, 'hp')) and not File.exists?(File.join($HPC_ACCOUNTS, sAccountName)) and sAccountName != 'hp'
|
114
|
+
Logging.info("hpcloud: Copying 'hp' account setup to '%s'" % sAccountName)
|
115
|
+
Kernel.system('hpcloud account:copy hp %s' % [sAccountName])
|
116
|
+
end
|
117
|
+
|
118
|
+
Logging.info("Configuring hpcloud account '%s'" % [sAccountName] )
|
119
|
+
command = 'hpcloud account:setup %s' % [sAccountName]
|
120
|
+
Logging.debug("Executing : '%s'" % command)
|
121
|
+
case Kernel.system(command)
|
122
|
+
when false
|
123
|
+
Logging.fatal(1, "Unable to setup your hpcloud account")
|
124
|
+
when nil
|
125
|
+
Logging.fatal(1, "Unable to execute 'hpcloud' cli. Please check hpcloud installation.")
|
126
|
+
end
|
127
|
+
|
128
|
+
if not oConfig.yConfig['default'].has_key?('account')
|
129
|
+
oConfig.LocalSet('account',sAccountName)
|
130
|
+
oConfig.SaveConfig
|
131
|
+
end
|
132
|
+
|
133
|
+
# Loading HPCloud account setting in Config.
|
134
|
+
hpc_account_file = File.join($HPC_ACCOUNTS, sAccountName)
|
135
|
+
|
136
|
+
# Maestro compute use openstack. It requires meta tenant_name (not ID). Need to query HPC to get the Project Name from the ID.
|
137
|
+
oConfig.ExtraLoad(hpc_account_file, :hpc_accounts, sAccountName)
|
67
138
|
|
68
|
-
|
69
|
-
|
139
|
+
setup_tenant_name(oConfig, sAccountName)
|
140
|
+
end
|
141
|
+
|
142
|
+
def setup_dns(oConfig, sAccountName)
|
143
|
+
sAsk = "Optionally, you can ask Maestro to manage a Domain name. It requires your DNS cloud service to be enabled.\nDo you want to configure it?"
|
144
|
+
if agree(sAsk)
|
145
|
+
# Get HPCloud account definition
|
146
|
+
yHPC = oConfig.ExtraGet(:hpc_accounts, sAccountName)
|
147
|
+
|
148
|
+
# Get Forj account definition
|
149
|
+
yDNS = oConfig.ExtraGet(:forj_accounts, sAccountName, :dns)
|
150
|
+
yDNS = {} if not yDNS
|
70
151
|
|
71
|
-
#
|
72
|
-
|
152
|
+
# Getting tenants
|
153
|
+
tenants = oConfig.get('tenants')
|
154
|
+
|
155
|
+
# Question about DNS Tenant ID
|
156
|
+
# In HPCloud : credentials/tenant_id
|
157
|
+
aDNS_TenantIDs = []
|
158
|
+
sDNS_TenantIDs = rhGet(yDNS, :tenant_id)
|
159
|
+
sDNS_TenantIDs = rhGet(yHPC, :credentials, :tenant_id) if not sDNS_TenantIDs and rhExist?(yHPC, :credentials, :tenant_id) > 0
|
160
|
+
|
161
|
+
Logging.message("Following are the list of know project attached to your credentials:")
|
162
|
+
tenants.each do | elem |
|
163
|
+
aDNS_TenantIDs.push(elem['id'])
|
164
|
+
if sDNS_TenantIDs and elem['id'] == sDNS_TenantIDs
|
165
|
+
Logging.message("%s - %s" % [ANSI.bold+elem['id']+ANSI.reset, elem['name']])
|
166
|
+
else
|
167
|
+
Logging.message("%s - %s" % [elem['id'], elem['name']])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
sOption = ' [%s]' % aDNS_TenantIDs.join(', ') if aDNS_TenantIDs.length() == 2
|
172
|
+
sDNS_TenantID = ask('Enter DNS Tenant ID:%s' % sOption) do |q|
|
173
|
+
q.default = sDNS_TenantIDs
|
174
|
+
q.validate = /[\w\d]+/
|
175
|
+
end
|
176
|
+
yDNS[:tenant_id] = sDNS_TenantID.to_s
|
177
|
+
|
178
|
+
# Question about DNS Service
|
179
|
+
# In HPCloud : regions/dns
|
180
|
+
if sDNS_TenantID == rhGet(yHPC, :credentials, :tenant_id)
|
181
|
+
sDNS_Service = rhGet(yHPC, :regions, :dns)
|
182
|
+
else
|
183
|
+
aDNS_Services = []
|
184
|
+
aDNS_Services.push(rhGet(yDNS, :service)) if rhExist?(yDNS, :service) > 0
|
73
185
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
186
|
+
sDNS_Service = ask("Enter DNS Service for the Tenant ID '%s' (ex: region-a.geo-1): " % sDNS_TenantID) do |q|
|
187
|
+
q.validate = /[\w.-]+/
|
188
|
+
end
|
189
|
+
end
|
190
|
+
yDNS[:service] = sDNS_Service.to_s
|
191
|
+
|
192
|
+
else
|
193
|
+
yDNS = {} # Any information about DNS setting is removed.
|
194
|
+
Logging.message("Maestro won't manage any Domain.")
|
195
|
+
end
|
196
|
+
# Question about Domain name
|
197
|
+
previousDomainName = rhGet(yDNS, :domain_name) if rhExist?(yDNS, :domain_name) > 0
|
198
|
+
|
199
|
+
sDNS_DomainName = ask('Enter Domain name (puppet requirement) (ex: dev.forj.io):') do |q|
|
200
|
+
q.default = previousDomainName if previousDomainName
|
201
|
+
q.validate = /[\w._]+/
|
202
|
+
end
|
203
|
+
yDNS[:domain_name] = sDNS_DomainName.to_s
|
204
|
+
|
205
|
+
oConfig.ExtraSet(:forj_accounts, sAccountName, :dns, yDNS)
|
206
|
+
forjAccountFile = File.join($FORJ_ACCOUNTS_PATH, sAccountName)
|
207
|
+
oConfig.ExtraSave(forjAccountFile, :forj_accounts, sAccountName)
|
80
208
|
end
|
81
209
|
|
82
210
|
def ensure_forj_dirs_exists()
|
@@ -84,19 +212,20 @@ def ensure_forj_dirs_exists()
|
|
84
212
|
|
85
213
|
# Defining Global variables
|
86
214
|
$FORJ_DATA_PATH = File.expand_path(File.join('~', '.forj'))
|
87
|
-
$
|
215
|
+
$FORJ_ACCOUNTS_PATH = File.join($FORJ_DATA_PATH, 'accounts')
|
88
216
|
$FORJ_KEYPAIRS_PATH = File.join($FORJ_DATA_PATH, 'keypairs')
|
89
217
|
$FORJ_CREDS_PATH = File.expand_path(File.join('~', '.cache', 'forj'))
|
90
|
-
|
218
|
+
|
91
219
|
# TODO: To move to an hpcloud object.
|
92
220
|
$HPC_KEYPAIRS = File.expand_path(File.join('~', '.hpcloud', 'keypairs'))
|
221
|
+
$HPC_ACCOUNTS = File.expand_path(File.join('~', '.hpcloud', 'accounts'))
|
93
222
|
|
94
223
|
Helpers.ensure_dir_exists($FORJ_DATA_PATH)
|
95
|
-
Helpers.ensure_dir_exists($
|
224
|
+
Helpers.ensure_dir_exists($FORJ_ACCOUNTS_PATH)
|
96
225
|
Helpers.ensure_dir_exists($FORJ_KEYPAIRS_PATH)
|
97
226
|
Helpers.ensure_dir_exists($FORJ_CREDS_PATH)
|
98
227
|
end
|
99
|
-
|
228
|
+
|
100
229
|
def keypair_setup(oConfig)
|
101
230
|
|
102
231
|
key_path = oConfig.get('keypair_path')
|
@@ -122,59 +251,77 @@ def keypair_setup(oConfig)
|
|
122
251
|
Logging.debug("Saving forj keypair '%s' as default." % [real_key_path] )
|
123
252
|
oConfig.LocalSet('keypair_path', real_key_path)
|
124
253
|
oConfig.SaveConfig()
|
125
|
-
end
|
254
|
+
end
|
126
255
|
end
|
127
256
|
end
|
128
257
|
end
|
129
258
|
|
130
259
|
|
131
|
-
def save_maestro_creds(sAccountName)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
260
|
+
def save_maestro_creds(oConfig, sAccountName)
|
261
|
+
# Check required global data
|
262
|
+
if not $FORJ_CREDS_PATH
|
263
|
+
Logging.fatal(1, "Internal error: '$FORJ_CREDS_PATH' missing.")
|
264
|
+
end
|
265
|
+
if not Helpers.dir_exists?($FORJ_CREDS_PATH)
|
266
|
+
Logging.fatal(1, "Internal error: '%s' doesn't exist." % $FORJ_CREDS_PATH)
|
267
|
+
end
|
139
268
|
|
140
|
-
|
269
|
+
Logging.info("Completing hpcloud account '%s' information." % [sAccountName] )
|
141
270
|
|
142
|
-
|
143
|
-
|
144
|
-
q.validate = /\w+/
|
145
|
-
q.default = ''
|
146
|
-
end
|
271
|
+
forjAccountFile = File.join($FORJ_ACCOUNTS_PATH, sAccountName)
|
272
|
+
oConfig.ExtraLoad(forjAccountFile, :forj_accounts, sAccountName)
|
147
273
|
|
148
|
-
|
149
|
-
q.echo = '*'
|
150
|
-
q.validate = /.+/
|
151
|
-
end
|
274
|
+
forj_user = rhGet(oConfig.ExtraGet(:forj_accounts, sAccountName, :credentials), :os_user)
|
152
275
|
|
153
|
-
|
276
|
+
hpcloud_os_user = ask('Enter hpcloud username: ') do |q|
|
277
|
+
q.validate = /\w+/
|
278
|
+
q.default = forj_user if forj_user
|
279
|
+
end
|
280
|
+
|
281
|
+
hpcloud_os_key = ask("Enter hpcloud password for '%s': " % hpcloud_os_user) do |q|
|
282
|
+
q.echo = '*'
|
283
|
+
q.validate = /.+/
|
284
|
+
end
|
154
285
|
|
155
|
-
|
286
|
+
# Checking key file used to encrypt/decrypt passwords
|
287
|
+
key_file = File.join($FORJ_CREDS_PATH, '.key')
|
288
|
+
if not File.exists?(key_file)
|
289
|
+
# Need to create a random key.
|
290
|
+
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}
|
291
|
+
|
292
|
+
Logging.debug("Writing '%s' key file" % key_file)
|
293
|
+
File.open(key_file, 'w') do |out|
|
294
|
+
out.write(Base64::encode64(entr.to_yaml))
|
295
|
+
end
|
296
|
+
else
|
297
|
+
Logging.debug("Loading '%s' key file" % key_file)
|
298
|
+
encoded_key = IO.read(key_file)
|
299
|
+
entr = YAML.load(Base64::decode64(encoded_key))
|
300
|
+
end
|
301
|
+
enc_hpcloud_os_key = Base64::strict_encode64(Encryptor.encrypt(:value => hpcloud_os_key, :key => entr[:key], :iv => entr[:iv], :salt => entr[:salt]))
|
156
302
|
|
157
|
-
|
158
|
-
old_file = '%s/master.forj-13.5' % [$FORJ_CREDS_PATH]
|
159
|
-
File.delete(old_file) if File.exists?(old_file)
|
160
|
-
old_file = '%s/creds' % [$FORJ_CREDS_PATH]
|
161
|
-
File.delete(old_file) if File.exists?(old_file)
|
303
|
+
cloud_fog = File.join($FORJ_CREDS_PATH, sAccountName+'.g64')
|
162
304
|
|
163
|
-
|
164
|
-
|
305
|
+
# Security fix: Remove old temp file with clear password.
|
306
|
+
old_file = '%s/master.forj-13.5' % [$FORJ_CREDS_PATH]
|
307
|
+
File.delete(old_file) if File.exists?(old_file)
|
308
|
+
old_file = '%s/creds' % [$FORJ_CREDS_PATH]
|
309
|
+
File.delete(old_file) if File.exists?(old_file)
|
165
310
|
|
166
|
-
|
167
|
-
secret_key = creds[:credentials][:secret_key]
|
311
|
+
hpc_creds = oConfig.ExtraGet(:hpc_accounts, sAccountName, :credentials)
|
168
312
|
|
169
|
-
|
170
|
-
|
313
|
+
forj_creds = { :os_user => hpcloud_os_user.to_s,
|
314
|
+
:os_enckey => enc_hpcloud_os_key
|
315
|
+
}
|
316
|
+
oConfig.ExtraSet(:forj_accounts, sAccountName, :credentials, forj_creds)
|
317
|
+
oConfig.ExtraSave(forjAccountFile, :forj_accounts, sAccountName)
|
171
318
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
319
|
+
IO.popen('gzip -c | base64 -w0 > %s' % [cloud_fog], 'r+') {|pipe|
|
320
|
+
pipe.puts('HPCLOUD_OS_USER=%s' % [hpcloud_os_user] )
|
321
|
+
pipe.puts('HPCLOUD_OS_KEY=%s' % [hpcloud_os_key] )
|
322
|
+
pipe.puts('DNS_KEY=%s' % [hpc_creds[:account_id]] )
|
323
|
+
pipe.puts('DNS_SECRET=%s' % [hpc_creds[:secret_key]])
|
324
|
+
pipe.close_write
|
325
|
+
}
|
326
|
+
Logging.info("'%s' written." % cloud_fog)
|
180
327
|
end
|
data/lib/ssh.sh
CHANGED
@@ -19,7 +19,7 @@ GRE="\e[92m"
|
|
19
19
|
# See the License for the specific language governing permissions and
|
20
20
|
# limitations under the License.
|
21
21
|
|
22
|
-
|
22
|
+
NOW=$(date +%Y-%m-%d.%H%M%S)
|
23
23
|
logpath=~/.ssh/
|
24
24
|
DB=~/hosts
|
25
25
|
#key_path=~/.ssh/
|
@@ -140,7 +140,7 @@ else
|
|
140
140
|
echo -e "${RED}Error, the kit ${GRE}$node${RED} with id ${GRE}$id${RED} was not found.${RST}"
|
141
141
|
exit 1
|
142
142
|
fi
|
143
|
-
key=$(cat $DB | grep -
|
143
|
+
key=$(cat $DB | grep -iEw "$ip" | awk '{print $4}' | tr -d ' ')
|
144
144
|
message="$node.$id"
|
145
145
|
extended="($ip)"
|
146
146
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.37
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- forj team
|
@@ -14,14 +14,14 @@ dependencies:
|
|
14
14
|
name: thor
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.16.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.16.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.0.
|
61
|
+
version: 2.0.9
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.0.
|
68
|
+
version: 2.0.9
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: git
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,7 +145,6 @@ files:
|
|
145
145
|
- lib/ssh.sh
|
146
146
|
- lib/log.rb
|
147
147
|
- lib/helpers.rb
|
148
|
-
- lib/build_tmpl/build-env.py
|
149
148
|
- lib/forj-config.rb
|
150
149
|
- spec/boot_spec.rb
|
151
150
|
- spec/connection_spec.rb
|