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.
data/lib/forj-config.rb CHANGED
@@ -30,7 +30,7 @@ class ForjDefault
30
30
  # @yDefaults = defaults.yaml file data hash
31
31
 
32
32
  attr_reader :yDefaults
33
-
33
+
34
34
  def initialize()
35
35
  # Load yaml documents (defaults)
36
36
  # If config doesn't exist, it will be created, empty with 'defaults:' only
@@ -38,7 +38,7 @@ class ForjDefault
38
38
  if not $LIB_PATH
39
39
  Logging.fatal(1, 'Internal $LIB_PATH was not set.')
40
40
  end
41
-
41
+
42
42
  Logging.info ('Reading default configuration...')
43
43
 
44
44
  @sDefaultsName=File.join($LIB_PATH,'defaults.yaml')
@@ -48,14 +48,14 @@ class ForjDefault
48
48
 
49
49
  end
50
50
 
51
- class ForjConfig
51
+ class ForjConfig
52
52
 
53
53
  # Internal variables:
54
54
  # @sConfigName='config.yaml'
55
55
  # @yRuntime = data in memory.
56
56
  # @yLocal = config.yaml file data hash.
57
57
  # @yConfig = defaults.yaml + local_config data hash
58
-
58
+
59
59
  attr_reader :yLocal
60
60
  attr_reader :yConfig
61
61
  attr_reader :sConfigName
@@ -64,7 +64,6 @@ class ForjConfig
64
64
  # Load yaml documents (defaults + config)
65
65
  # If config doesn't exist, it will be created, empty with 'defaults:' only
66
66
 
67
-
68
67
  if not $FORJ_DATA_PATH
69
68
  Logging.fatal(1, 'Internal $FORJ_DATA_PATH was not set.')
70
69
  end
@@ -74,42 +73,34 @@ class ForjConfig
74
73
  if sConfigName
75
74
  if File.dirname(sConfigName) == '.'
76
75
  sConfigName= File.join($FORJ_DATA_PATH,sConfigName)
77
- end
76
+ end
78
77
  sConfigName = File.expand_path(sConfigName)
79
78
  if not File.exists?(sConfigName)
80
79
  Logging.warning("Config file '%s' doesn't exists. Using default one." % [sConfigName] )
81
80
  @sConfigName=File.join($FORJ_DATA_PATH,sConfigDefaultName)
82
- else
81
+ else
83
82
  @sConfigName=sConfigName
84
83
  end
85
84
  else
86
85
  @sConfigName=File.join($FORJ_DATA_PATH,sConfigDefaultName)
87
86
  end
88
87
 
89
-
90
88
  @Default=ForjDefault.new
91
-
92
-
89
+
93
90
  if File.exists?(@sConfigName)
94
91
  @yLocal=YAML.load_file(@sConfigName)
95
92
  else
96
93
  @yLocal={ 'default' => nil }
97
- if not File.exists?(@sConfigName)
98
- # Write the empty file
99
- if not File.exists?($FORJ_DATA_PATH)
100
- Dir.mkdir($FORJ_DATA_PATH)
101
- end
102
- Logging.info ('Creating your default configuration file ...')
103
- self.SaveConfig()
104
- end
94
+ # Write the empty file
95
+ Logging.info ('Creating your default configuration file ...')
96
+ self.SaveConfig()
105
97
  end
106
-
98
+
107
99
  BuildConfig()
108
-
100
+
109
101
  @yRuntime={}
110
102
  end
111
103
 
112
-
113
104
  def SaveConfig()
114
105
  begin
115
106
  File.open(@sConfigName, 'w') do |out|
@@ -122,7 +113,31 @@ class ForjConfig
122
113
  Logging.info ('Configuration file "%s" updated.' % @sConfigName)
123
114
  return true
124
115
  end
125
-
116
+
117
+ def ExtraSave(sFile, section, name)
118
+ hVal = rhGet(@Default.yDefaults, :extra_loaded, section, name)
119
+ if hVal
120
+ begin
121
+ File.open(sFile, 'w') do |out|
122
+ YAML.dump(hVal, out)
123
+ end
124
+ rescue => e
125
+ Logging.error("%s\n%s" % [e.message, e.backtrace.join("\n")])
126
+ return false
127
+ end
128
+ Logging.info ('Configuration file "%s" updated.' % sFile)
129
+ return true
130
+ end
131
+ end
132
+
133
+ def ExtraLoad(sFile, section, name)
134
+ if File.exists?(sFile)
135
+ hVal = YAML.load_file(sFile)
136
+ rhSet(@Default.yDefaults, hVal, :extra_loaded, section, name)
137
+ end
138
+ BuildConfig()
139
+ end
140
+
126
141
  def LocalSet(key, value, section = 'default')
127
142
  if not key or not value
128
143
  return false
@@ -134,70 +149,187 @@ class ForjConfig
134
149
  @yLocal[section].merge!({key => value})
135
150
  else
136
151
  @yLocal.merge!(section => {key => value})
137
- end
152
+ end
138
153
  BuildConfig()
139
154
  return true
140
155
  end
141
-
142
- def LocalDel(key,section = 'default')
156
+
157
+ def LocalGet(key, section = 'default', default = nil)
158
+ if @yLocal.has_key?(key)
159
+ return @yLocal[key]
160
+ end
161
+ default
162
+ end
163
+
164
+ def LocalDel(key, section = 'default')
143
165
  if not key
144
166
  return false
145
167
  end
146
168
  if not @yLocal.has_key?(section)
147
169
  return false
148
- end
170
+ end
149
171
  @yLocal[section].delete(key)
150
172
  BuildConfig()
151
173
  return true
152
174
  end
153
-
154
- def setDefault(key, value)
155
- if not key
156
- return false
157
- end
158
- if not @yRuntime[key]
159
- @yRuntime[key] = value
160
- end
161
- return true
175
+
176
+ def ExtraExist?(section, name, key)
177
+ return nil if not section or not name
178
+
179
+ return(rhExist?(@yConfig, :extra_loaded, section, name) == 3) if not key
180
+ return(rhExist?(@yConfig, :extra_loaded, section, name, key) == 4)
162
181
  end
163
-
164
- def set(key, value)
165
- if not key
166
- return false
167
- end
168
- if value
169
- @yRuntime[key] = value
170
- else
171
- @yRuntime.delete(key)
172
- end
173
- return true
182
+
183
+ def ExtraGet(section, name, key = nil, default = nil)
184
+ return nil if not section or not name
185
+
186
+ if key
187
+ return default unless ExtraExist?(section, name, key)
188
+ rhGet(@yConfig, :extra_loaded, section, name, key)
189
+ else
190
+ return default unless rhExist?(@yConfig, :extra_loaded, section, name) == 3
191
+ rhGet(@yConfig, :extra_loaded, section, name)
192
+ end
174
193
  end
175
-
176
- def get(key, default = @yConfig['default'][key])
177
- if @yRuntime.has_key?(key)
178
- @yRuntime[key]
179
- else
180
- default
181
- end
194
+
195
+ def ExtraSet(section, name, key, value)
196
+ rhSet(@yConfig, value, :extra_loaded, section, name, key)
197
+ end
198
+
199
+ def set(key, value, par = {})
200
+ # Function to set a config key, but remove it if value is nil.
201
+ if not key
202
+ return false
203
+ end
204
+ if par[:section] and par[:name]
205
+ # Set data in extra_loaded
206
+ ExtraSet(par[:section], par[:name], key, value)
207
+ elsif par[:section]
208
+ # To set key=value on config.yaml, use LocalSet
209
+ if value
210
+ rhSet(@yRuntime, value, par[:section], key)
211
+ else
212
+ hVal = rhGet(@yRuntime, par[:section])
213
+ hVal.delete(key)
214
+ end
215
+ else
216
+ if value
217
+ rhSet(@yRuntime, value, key)
218
+ else
219
+ @yRuntime.delete(key)
220
+ end
221
+ end
222
+ true
182
223
  end
183
-
224
+
225
+ def get(key, par = {})
226
+ if par[:section] and par[:name]
227
+ # Get data only from extra_loaded
228
+ return ExtraGet(par[:section], par[:name], key, par[:default])
229
+ elsif par[:section]
230
+ # If section/key is in runtime
231
+ return rhGet(@yRuntime, par[:section], key) if rhExist?(@yRuntime, par[:section], key) == 2
232
+ # If section/key is in default config
233
+ return rhGet(@yConfig, par[:section], key) if rhExist?(@yConfig, par[:section], key) == 2
234
+ else
235
+ # If key is in runtime
236
+ return rhGet(@yRuntime, key) if rhExist?(@yRuntime, key) == 1
237
+ end
238
+ # else key in default config of default section.
239
+ return rhGet(@yConfig, 'default', key) if rhExist?(@yConfig, 'default', key) == 2
240
+ # else default
241
+ par[:default]
242
+ end
243
+
244
+ def exist?(key, par = {})
245
+ if par[:section] and par[:name]
246
+ # section/name/key exist in extra_loaded ?
247
+ return ExtraExist?(par[:section], par[:name], key)
248
+ elsif par[:section]
249
+ # section/key exist in runtime?
250
+ return "runtime" if rhExist?(@yRuntime, par[:section], key) == 2
251
+ # section/key exist in default config ?
252
+ return "default" if rhExist?(@yConfig, par[:section], key) == 2
253
+ else
254
+ return "runtime" if rhExist?(@yRuntime, key) == 1
255
+ return "default" if rhExist?(@yRuntime, 'default', key) == 2
256
+ end
257
+ false
258
+ end
259
+
184
260
  def BuildConfig()
185
- # This function implements the logic to get defaults, superseed by local config.
261
+ # This function implements the logic to get defaults, superseed by local config.
186
262
  # Take care of ports array, which is simply merged.
187
-
188
- @yConfig={ 'default' => @Default.yDefaults['default'].clone }
263
+
264
+ @yConfig = @Default.yDefaults.clone
189
265
  if @yLocal['default']
190
266
  @yConfig['default'].merge!(@yLocal['default']) { |key, oldval, newval| key == 'ports'? newval.clone.push(oldval.clone).flatten: newval }
191
- end
192
- @yConfig.merge!(@yLocal) { |key, oldval, newval| key == 'default'? oldval: newval }
267
+ end
268
+ @yConfig.merge!(@yLocal) { |key, oldval, newval| (key == 'default' or key == :extra_load)? oldval: newval }
193
269
  end
194
-
270
+
195
271
  def LocalDefaultExist?(key)
196
- if @yLocal['default'][key]
197
- true
198
- else
199
- false
200
- end
272
+ return true if @yLocal['default'][key]
273
+ false
201
274
  end
202
275
 
276
+ def fatal_if_inexistent(key)
277
+ # Function to return in fatal error if a config data is nil. Help to control function requirement.
278
+ Logging.fatal(1, "Internal error - %s: '%s' is missing" % [caller(), key]) if not self.get(key)
279
+ end
280
+ end
281
+
282
+ def rhExist?(yVal, *p)
283
+
284
+ if p.length() == 0
285
+ return 0
286
+ end
287
+ return 0 if yVal.class != Hash
288
+ p=p.flatten
289
+ if p.length() == 1
290
+ return 1 if yVal[p[0]]
291
+ return 0
292
+ end
293
+ return 0 if not yVal or not yVal[p[0]]
294
+ ret = rhExist?(yVal[p[0]], p.drop(1)) if yVal[p[0]]
295
+ return 1 + ret
296
+ 0
297
+ end
298
+
299
+ def rhGet(yVal, *p)
300
+
301
+ if p.length() == 0 or not yVal
302
+ return nil
303
+ end
304
+ p=p.flatten
305
+ if p.length() == 1
306
+ return yVal[p[0]] if yVal[p[0]]
307
+ return nil
308
+ end
309
+ return nil if not yVal
310
+ return rhGet(yVal[p[0]], p.drop(1)) if yVal[p[0]]
311
+ nil
312
+ end
313
+
314
+ def rhSet(yVal, value, *p)
315
+ if p.length() == 0
316
+ return yVal
317
+ end
318
+ p=p.flatten
319
+ if p.length() == 1
320
+ if yVal
321
+ yVal[p[0]] = value
322
+ return yVal
323
+ end
324
+ ret = { p[0] => value }
325
+ return ret
326
+ end
327
+ if yVal
328
+ yVal[p[0]] = {} if not yVal[p[0]] or yVal[p[0]].class != Hash
329
+ ret=rhSet(yVal[p[0]], value, p.drop(1))
330
+ return yVal
331
+ else
332
+ ret = rhSet(nil, value, p.drop(1))
333
+ return { p[0] => ret }
334
+ end
203
335
  end
data/lib/repositories.rb CHANGED
@@ -28,6 +28,10 @@ include YamlParse
28
28
  #
29
29
  # Repositories module
30
30
  #
31
+
32
+ # Current version of the infra. Compatible with forj version or higher.
33
+ INFRA_VERSION = "37"
34
+
31
35
  module Repositories
32
36
  def clone_repo(maestro_url)
33
37
  current_dir = Dir.pwd
@@ -50,20 +54,115 @@ module Repositories
50
54
  Dir.chdir(current_dir)
51
55
  end
52
56
 
53
- def create_infra(maestro_repo)
54
- home = File.expand_path('~')
55
- path = home + '/.forj/'
56
- infra = path + 'infra/'
57
57
 
58
- if File.directory?(infra)
59
- FileUtils.rm_r(infra)
60
- end
61
- Dir.mkdir(infra)
62
58
 
63
- command = 'cp -rp ~/.forj/maestro/templates/infra/cloud-init ~/.forj/infra/'
64
- Kernel.system(command)
59
+ def create_infra(maestro_repo)
60
+ # Build our own infra from maestro infra templates.
61
+ infra = File.join($FORJ_DATA_PATH, 'infra')
62
+ dest_cloud_init = File.join(infra, 'cloud-init')
63
+ template = File.join(maestro_repo, 'templates', 'infra')
64
+ cloud_init = File.join(template, 'cloud-init')
65
65
 
66
- fill_template = 'python %s/build_tmpl/build-env.py -p ~/.forj/infra --maestro-path %s' % [$LIB_PATH, maestro_repo]
67
- Kernel.system(fill_template)
68
- end
66
+ if File.directory?(infra)
67
+ Logging.debug("Cleaning up '%s'" % [infra])
68
+ FileUtils.rm_r(infra)
69
+ end
70
+ Helpers.ensure_dir_exists(dest_cloud_init)
71
+ Logging.debug("Copying recursively '%s' to '%s'" % [cloud_init, infra])
72
+ FileUtils.copy_entry(cloud_init, dest_cloud_init)
73
+
74
+ build_env = File.join(template,'maestro.box.master.env')
75
+ Logging.debug("Copying '%s' to '%s'" % [build_env, infra])
76
+ FileUtils.copy(build_env, infra)
77
+
78
+ file_ver = File.join(infra, 'forj-cli.ver')
79
+ File.write(file_ver, $INFRA_VERSION)
80
+ end
81
+
82
+ def infra_rebuild_required?(oConfig, infra_dir)
83
+ # This function check if the current infra is compatible with current gem version.
84
+
85
+ # prior 0.0.37 - Use a template file of build env file.
86
+ # 0.0.37 - Using a generic version of build env file, fully managed by forj cli.
87
+ return false if not File.exists?(infra_dir)
88
+
89
+ if infra_dir != File.join($FORJ_DATA_PATH, 'infra')
90
+ # Do not take care. We do not manage it, ourself.
91
+ return false
92
+ end
93
+
94
+ file_ver = File.join(infra_dir, 'forj-cli.ver')
95
+ forj_infra_version = nil
96
+ forj_infra_version = File.read(file_ver) if File.exist?(file_ver)
97
+
98
+ if forj_infra_version
99
+ case forj_infra_version
100
+ when $INFRA_VERSION
101
+ return false
102
+ else
103
+ old_infra_data_update(oConfig, forj_infra_version, infra_dir)
104
+ end
105
+ else # Prior version 37
106
+ old_infra_data_update(oConfig, 36, infra_dir)
107
+ end
108
+ true
109
+ end
110
+
111
+ def old_infra_data_update(oConfig, version, infra_dir)
112
+ Logging.info("Migrating your local infra repo to the latest version.")
113
+ # Supporting old version.
114
+ case version
115
+ when 36
116
+ # Moving from 0.0.36 or less to 0.0.37 or higher.
117
+ # SET_COMPUTE="{SET_COMPUTE!}" => Setting for Compute. ignored. Coming from HPC
118
+ # SET_TENANT_NAME="{SET_TENANT_NAME!}" => Setting for Compute. ignored. Need to query HPC from current Tenant ID
119
+
120
+ # SET_DNS_TENANTID="{SET_DNS_TENANTID!}" => Setting for DNS. meta = dns_tenantid
121
+ # ==> :forj_accounts, sAccountName, :dns, :tenant_id
122
+
123
+ # SET_DNS_ZONE="{SET_DNS_ZONE!}" => Setting for DNS. meta = dns_zone
124
+ # ==> :forj_accounts, sAccountName, :dns, :service
125
+
126
+ # SET_DOMAIN="{SET_DOMAIN!}" => Setting for Maestro (required) and DNS if enabled.
127
+ # ==> :forj_accounts, sAccountName, :dns, :domain_name
128
+ sAccountName = oConfig.get('account_name')
129
+
130
+ yDns = {}
131
+ yDns = oConfig.ExtraGet(:forj_accounts, sAccountName, :dns) if oConfig.ExtraExist?(:forj_accounts, sAccountName, :dns)
132
+ build_env = File.join(infra_dir, 'maestro.box.master.env')
133
+ Logging.debug("Reading data from '%s'" % build_env)
134
+ tags = {'SET_DNS_TENANTID' => :tenant_id,
135
+ 'SET_DNS_ZONE' => :service,
136
+ 'SET_DOMAIN' => :domain_name
137
+ }
138
+ begin
139
+ bUpdate = nil
140
+
141
+ File.open(build_env) do |f|
142
+ f.each_line do |line|
143
+ mObj = line.match(/^(SET_[A-Z_]+)=["'](.*)["'].*$/)
144
+ if mObj
145
+ Logging.debug("Reviewing detected '%s' tag" % [mObj[1]])
146
+ tag = (tags[mObj[1]]? tags[mObj[1]] : nil)
147
+ if tag and mObj[2]
148
+ if bUpdate == nil and rhGet(yDns, tag) and rhGet(yDns, tag) != mObj[2]
149
+ Logging.message("Your account setup is different than build env.")
150
+ Logging.message("We suggest you to update your account setup with data from your build env.")
151
+ bUpdate = agree("Do you want to update your setup with those build environment data?")
152
+ end
153
+ if bUpdate != nil and bUpdate
154
+ Logging.debug("Saved: '%s' = '%s'" % [mObj[1],mObj[2]])
155
+ rhSet(yDns, mObj[2], tag)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ rescue => e
162
+ Logging.fatal(1, "Unable to open the build environment file to migrate it\n%s" % e.backtrace.join('\n'))
163
+ end
164
+ oConfig.ExtraSet(:forj_accounts, sAccountName, :dns, yDns)
165
+ oConfig.ExtraSave(File.join($FORJ_ACCOUNTS_PATH, sAccountName), :forj_accounts, sAccountName)
166
+ end
167
+ end
69
168
  end
data/lib/security.rb CHANGED
@@ -137,20 +137,42 @@ module SecurityGroup
137
137
  rule
138
138
  end
139
139
 
140
- def hpc_import_pubkey(oConfig, account)
140
+ def hpc_import_key(oConfig, account)
141
141
 
142
142
  key_name = oConfig.get('keypair_name')
143
143
  key_path = oConfig.get('keypair_path')
144
144
 
145
+ mObj = key_path.match(/^(.*)(\.pem)?$/)
146
+
147
+ key_path = mObj[1]
148
+
145
149
  Logging.fatal(1, "'keypair_path' undefined. check your config.yaml file.") if not key_path
146
150
  Logging.fatal(1, "'keypair_name' undefined. check your config.yaml file.") if not key_name
147
151
 
148
152
  pubkey_path = key_path + '.pub'
149
153
  Logging.fatal(1, "keypair '%s' are missing. Please call 'forj setup %s' to create the missing key pair required." % [pubkey_path, account]) if not File.exists?(pubkey_path)
150
-
151
- Logging.info("Importing your forj keypair '%s' to hpcloud." % pubkey_path)
152
- command = 'hpcloud keypairs:import %s %s -a %s' % [key_name, pubkey_path, account]
153
- Logging.debug("Executing command '%s'" % command)
154
- Kernel.system(command)
154
+ if not File.exists?(File.join($HPC_KEYPAIRS, key_name + '.pub'))
155
+ Logging.info("Importing your forj public key '%s' to hpcloud." % pubkey_path)
156
+ command = 'hpcloud keypairs:import %s %s -a %s' % [key_name, pubkey_path, account]
157
+ Logging.debug("Executing command '%s'" % command)
158
+ Kernel.system(command)
159
+ else
160
+ Logging.info("Using '%s' as public key." % pubkey_path)
161
+ end
162
+ private_key = nil
163
+ private_key = key_path if File.exists?(key_path)
164
+ private_key = key_path + '.pem' if File.exists?(key_path + '.pem')
165
+ if not File.exists?(File.join($HPC_KEYPAIRS, key_name + '.pem'))
166
+ if private_key
167
+ Logging.info("Importing your forj private key '%s' to hpcloud." % private_key)
168
+ command = 'hpcloud keypairs:private:add %s %s' % [key_name, private_key]
169
+ Logging.debug("Executing command '%s'" % command)
170
+ Kernel.system(command)
171
+ else
172
+ Logging.warning('Unable to find the private key. This will be required to access with ssh to Maestro and any blueprint boxes.')
173
+ end
174
+ else
175
+ Logging.info("Using '%s' as private key." % key_path)
176
+ end
155
177
  end
156
178
  end