forj 0.0.36 → 0.0.37
Sign up to get free protection for your applications and to get access to all the features.
- 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
|