satops 1.5.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c50c6ccd15bff68d7d331e38292b7d1eef82b28e
4
+ data.tar.gz: b9aee7b12949d768be4f3e2913aaabbcf050ef96
5
+ SHA512:
6
+ metadata.gz: 5924fc672cbff9eb174cc6557cd03309c7f8620da06a4b1949cb974df83ffaf2410850c4c2434350f37633a1169a1b938587d2aaefc1ff98ab7616be219e519e
7
+ data.tar.gz: 3a1c18114cb95595e52e5fccffd171408780a8ef75a0f65cda39eb447ddb81db29942b5a996ad94643a64e60338b3d279b98b7c5a3bb494bf2cd1d19db545339
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'satops'
4
+
5
+ Launcher.new(ARGV)
@@ -0,0 +1,495 @@
1
+ #!/usr/bin/env ruby
2
+ @@version='1.5.0'
3
+ =begin header
4
+ * Name: satops
5
+ * Description: RHN Satellite API Operator
6
+ * URL: https://github.com/SatOps/SatOps
7
+ * Date: 10 Nov 2013
8
+ * Author: Gilles Dubreuil <gilles@redhat.com>
9
+ * License: Copyright 2011, 2013 Gilles Dubreuil
10
+
11
+ This file is part of SatOps.
12
+
13
+ SatOps is free software: you can redistribute it and/or modify
14
+ it under the terms of the GNU General Public License as published by
15
+ the Free Software Foundation, either version 3 of the License, or
16
+ (at your option) any later version.
17
+
18
+ SatOps is distributed in the hope that it will be useful,
19
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ GNU General Public License for more details.
22
+
23
+ You should have received a copy of the GNU General Public License
24
+ along with SatOps. If not, see <http://www.gnu.org/licenses/>.
25
+ =end
26
+
27
+ =begin rdoc
28
+ Commands provided as parameters at command line are filtered by the Launcher class.
29
+ The latter creates a SatOperator object coordinating the operation.
30
+
31
+ The "Operation" Groups correspond to RHN Satellite objects such as Activation Keys, Software channels, etc.
32
+
33
+ The SatOperator controls the initial command execution flow for each Operation group.
34
+ Every Operation Group builds OperationSet objects, i.e RHN Satellite Set of objects, providing interface to RHN Satellite API to manipulate list of those objects.
35
+
36
+ At lower level, are RHN Satellite equivalent objects to be copied from or to a Satellite.
37
+
38
+ Example with RHN Satellite Activation keys.
39
+ Activationkey - Class mapping with RHN Satellite objects
40
+ Low level as it interface with RHN API
41
+
42
+ ActivationkeysSet - Notice plural before the Set
43
+ Subclass of OperationSet
44
+ Wrap/interface/group Activationkey objects
45
+
46
+ Activationkeys
47
+ Subclass of Operation
48
+ High level view, interfacing commands (export/import/sync,etc) to execute onto the ActivationkeysSet or Activationkey objects.
49
+
50
+ List of all Operations classes:
51
+ Activationkeys, Channels, Configchannels, Kickstarts, KickstartFilepreservations, KickstartKeys, KickstartSnippets, Orgs, OrgTrusts, Systems, SystemCustominfos, Systemgroups, Users
52
+ =end
53
+
54
+ require "logger"
55
+ require "xmlrpc/client"
56
+ require 'yaml'
57
+
58
+ def overwrite_net_http
59
+ # https: Client certificate isn't verified by server so each session generates:
60
+ # "warning: peer certificate won't be verified in this SSL session"
61
+ # To get rid of this warning: thanks to http://www.5dollarwhitebox.org/drupal/node/64
62
+ Net::HTTP.class_eval do
63
+ alias_method :old_initialize, :initialize
64
+ def initialize(*args)
65
+ old_initialize(*args)
66
+ @ssl_context = OpenSSL::SSL::SSLContext.new
67
+ @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
68
+ end
69
+ end
70
+ end
71
+
72
+ require 'satops/helpers'
73
+ require 'satops/rhsat'
74
+ require 'satops/operator'
75
+
76
+ def syntax
77
+ %s{
78
+ satops #{@@version}
79
+
80
+ Usage:
81
+ satops show sat | config
82
+ satops -s <sat file> -c <config file> [-dltw] destroy
83
+ satops -s <sat file> -c <config file> [-dltw] export <directory> ascii | bin
84
+ satops -s <sat file> -c <config file> [-dltw] import <directory> ascii | bin
85
+ satops -s <sat file> -c <config file> [-dltw] run <Ruby file>
86
+ satops -s <sat file> -c <config file> [-dltw] extras
87
+ satops -s <sat file> -c <config file> [-dltw] sync
88
+ satops [-h]
89
+
90
+ Mandatory Configuration:
91
+ Sat file: Source and Target RHN Satellites definition
92
+ Config file: RHN Satellite objects and options
93
+ Objects must be included to be processed
94
+ Use 'show sat|config' command for generating either templates
95
+
96
+ Options:
97
+ -d, --debug Activate debug output
98
+ -l, --log Append logs to file. By default logs go to Standard Output
99
+ -t, --tls Activate SSL (HTTPS) sessions
100
+ -w, --warnings Activate Ruby Verbose
101
+
102
+ -h, --help Display Version number, help and exit
103
+
104
+ Commands:
105
+ destroy Delete all objects on target RHN Satellite
106
+ export Export RHN Satellite objects to files (ascci or binary formats) into <directory>
107
+ extras Remove objects on target RHN Satellite not present in source RHN Satellite
108
+ import Import RHN Satellite object from files (ascii or binary) located into <directory>
109
+ run Execute Ruby 'plug-in' file
110
+ sync Synchronise objects from source RHN Satellite to target RHN Satellite
111
+ show Generate configuration file examples
112
+ }
113
+ end
114
+
115
+ def config_syntax
116
+ %s{
117
+ # SatOps YAML comprehensive configuration file example
118
+ #
119
+ # Red Hat Network Satellite object groups
120
+ # Activation Keys, Kickstart Profile, etc, with their specific options
121
+ # An object group must be must be present to have a command executed against it
122
+ #
123
+ # Options
124
+ # 'update' is a common option to allow corresponding object on target to be updated or not
125
+ # Options are not mandatory - Default values are always either false, '' (empty) or nil
126
+ #
127
+ # Notes
128
+ # YAML Format
129
+ # Respect indentations using spaces not tabulations
130
+ # Boolean values can be either yes/no or true/false
131
+ # Receivers - left part of assignment are keywords: Do not change them!
132
+ #
133
+ Activationkeys:
134
+ update: true
135
+ Configchannels:
136
+ update: true
137
+ # 'exclude' option provide a way to ignore some Config Channel objects
138
+ # This is a list of regular expressions - Replace
139
+ #exclude:
140
+ # - !ruby/regexp /^name1$/
141
+ # - !ruby/regexp /^name2$/
142
+ Channels:
143
+ update: true
144
+ delete: false
145
+ # Triggers satellite-sync on Target providing the Source software channels
146
+ iss: false
147
+ Kickstarts:
148
+ update: true
149
+ KickstartFilepreservations:
150
+ update: true
151
+ KickstartKeys:
152
+ update: true
153
+ # Type of keys. Default value is GPG. Other value would be SSL
154
+ key_type: GPG
155
+ KickstartSnippets:
156
+ update: true
157
+ Orgs:
158
+ update: true
159
+ entitlements: false
160
+ OrgTrusts:
161
+ update: true
162
+ SystemCustominfos:
163
+ update: true
164
+ Systems:
165
+ update: true
166
+ Systemgroups:
167
+ update: true
168
+ Users:
169
+ update: true
170
+ # Ignore deactivated users
171
+ deactivated: false
172
+ # By default extras users are deactivated not deleted
173
+ delete: false
174
+ # List of accounts to ignore
175
+ exclude:
176
+ - admin
177
+ - satadmin
178
+ # Default password used when creating user on target
179
+ # It cannot be blank
180
+ # When not using password then make sure PAM is activated
181
+ password: "rhnapi"
182
+ }
183
+ end
184
+
185
+ def satellites_syntax
186
+ %s{
187
+ # This is an example of a Satellite configuration file for the satOps
188
+ #
189
+ # This is a YAML formatted file
190
+ # Respect indentations using spaces not tabulations
191
+ # Boolean values can be either yes/no or true/false
192
+ #
193
+ # Do not remove any line
194
+ # Change only login and passwd values
195
+ --- !ruby/object:Configuration
196
+ source: !ruby/object:Host
197
+ name: sat1.example.org
198
+ user:
199
+ :login: admin
200
+ :passwd: redhat
201
+ target: !ruby/object:Host
202
+ name: sat2.example.org
203
+ user:
204
+ :login: admin
205
+ :passwd: redhat
206
+ }
207
+ end
208
+
209
+ class Configuration
210
+ attr_reader :source, :target
211
+ end
212
+
213
+ class Host
214
+ attr_reader :name
215
+
216
+ def login
217
+ @user[:login]
218
+ end
219
+
220
+ def auth
221
+ @user[:passwd]
222
+ end
223
+ end
224
+
225
+ # Satellite Interfacer
226
+ class SatOperator
227
+ attr_reader :source, :target, :operations
228
+
229
+ # Operations are ordered - It matters for object dependencies
230
+ OPS = [Orgs,
231
+ OrgTrusts,
232
+ Systemgroups,
233
+ Configchannels,
234
+ SystemCustominfos,
235
+ Systems,
236
+ Users,
237
+ Channels,
238
+ Activationkeys,
239
+ KickstartFilepreservations,
240
+ KickstartKeys,
241
+ KickstartSnippets,
242
+ Kickstarts]
243
+
244
+ def initialize(options, log)
245
+ @log=log
246
+ @operations=Array.new
247
+
248
+ OPS.each do |klass|
249
+ if options.has_key?(klass.to_s)
250
+ # Populate options (class variables) with their values
251
+ klass.class_eval do
252
+ options[klass.to_s].each do |key, val|
253
+ self.instance_variable_set("@#{key}", val)
254
+ end
255
+ end
256
+ # Create Operation objects
257
+ @operations << klass.class_eval { self.new(log) }
258
+ end
259
+ end
260
+ end
261
+
262
+ def destroy(target)
263
+ @operations.each do |op|
264
+ op.destroy(target)
265
+ end
266
+ end
267
+
268
+ def export(type, sat_source, path)
269
+ @operations.each do |op|
270
+ case type
271
+ when :bin
272
+ op.export(:mrb, sat_source, path)
273
+ when :ascii
274
+ op.export(:yaml, sat_source, path)
275
+ else
276
+ raise "FATAL: No such export format"
277
+ end
278
+ end
279
+ end
280
+
281
+ # Extra objects are only present in destination
282
+ # Delete is default operation unless overloaded by OperationSet subclasses.
283
+ def extra(*args)
284
+ @operations.each do |op|
285
+ op.extra(*args)
286
+ end
287
+ end
288
+
289
+ def import(type, *args)
290
+ @operations.each do |op|
291
+ case type
292
+ when :bin
293
+ op.import(:mrb, *args)
294
+ when :ascii
295
+ op.import(:yaml, *args)
296
+ else
297
+ raise "FATAL: No such import format"
298
+ end
299
+ end
300
+ end
301
+
302
+ def sync(*args)
303
+ @operations.each do |op|
304
+ op.sync(*args)
305
+ end
306
+ end
307
+
308
+ def context
309
+ str="\nSatellite Synchronisation Context:\n"
310
+ str << "#{@operations}\n"
311
+ end
312
+ end
313
+
314
+ class Launcher
315
+ def self.usage
316
+ puts syntax
317
+ exit
318
+ end
319
+
320
+ def operation_size?(param, size)
321
+ if param.size != size
322
+ Launcher.usage
323
+ end
324
+ end
325
+
326
+ def init_source
327
+ RHN::Session.running?(@sat_config.source.name, @ssl)
328
+ @sat_source=RHN::Satellite.new(@sat_config.source, @ssl, @log)
329
+ @sat_source.connect(@sat_config.source)
330
+ end
331
+
332
+ def init_target
333
+ RHN::Session.running?(@sat_config.target.name, @ssl)
334
+ @sat_target=RHN::Satellite.new(@sat_config.target, @ssl, @log)
335
+ @sat_target.connect(@sat_config.target)
336
+ end
337
+
338
+ def initialize(params)
339
+ @command=""
340
+ @config_file=nil
341
+ @file_to_run=nil
342
+ @options=nil
343
+ @log_file=STDOUT
344
+ @sat_file=nil
345
+ @sat_source=nil
346
+ @sat_target=nil
347
+ @ssl=false
348
+
349
+ unless (params.include?('-s') && params.include?('-c')) || params.include?('show')
350
+ Launcher.usage
351
+ end
352
+
353
+ until params.empty?
354
+ case params[0]
355
+ when '-c', '--config='
356
+ params.shift
357
+ @config_file=params[0]
358
+ when '-d', '--debug'
359
+ $DEBUG=true
360
+ when '-h', '--help'
361
+ Launcher.usage
362
+ when '-t', '--tls'
363
+ @ssl=true
364
+ overwrite_net_http
365
+ when '-l', '--log='
366
+ params.shift
367
+ @log_file=params[0]
368
+ when '-s', '--satfile='
369
+ params.shift
370
+ @sat_file=params[0]
371
+ when '-w', '--warnings'
372
+ $VERBOSE=true
373
+ when 'clone'
374
+ operation_size?(params, 3)
375
+ @command='clone'
376
+ params.shift
377
+ @name=params[0].to_sym
378
+ params.shift
379
+ @new_name=params[0]
380
+ when 'destroy'
381
+ operation_size?(params, 1)
382
+ @command='destroy'
383
+ when 'sync'
384
+ operation_size?(params, 1)
385
+ @command='sync'
386
+ when 'extras'
387
+ operation_size?(params, 1)
388
+ @command='extra'
389
+ when 'export'
390
+ operation_size?(params, 3)
391
+ @command='export'
392
+ params.shift
393
+ @path=params[0]
394
+ params.shift
395
+ @format=params[0].to_sym
396
+ when 'import'
397
+ operation_size?(params, 3)
398
+ @command='import'
399
+ params.shift
400
+ @path=params[0]
401
+ params.shift
402
+ @format=params[0].to_sym
403
+ when 'run'
404
+ operation_size?(params, 2)
405
+ @command='run'
406
+ params.shift
407
+ @file_to_run=params[0]
408
+ when 'show'
409
+ params.shift
410
+ case params[0]
411
+ when 'sat'
412
+ puts satellites_syntax
413
+ when 'config'
414
+ puts config_syntax
415
+ else
416
+ puts "Use 'show sat' or 'show config' commands"
417
+ end
418
+ exit
419
+ else
420
+ Launcher.usage
421
+ end
422
+ params.shift
423
+ end
424
+
425
+ begin
426
+ @log = Logger.new(@log_file)
427
+ @log.datetime_format = "%d/%m/%Y %H:%M:%S"
428
+ if $DEBUG
429
+ @log.level = Logger::DEBUG
430
+ else
431
+ @log.level = Logger::INFO
432
+ end
433
+ @log.info("Starting #{@command.upcase} command")
434
+
435
+ # Load satellites details file
436
+ File.open(@sat_file) do |f|
437
+ @sat_config = YAML.load(f)
438
+ end
439
+
440
+ # Load operations configuration file
441
+ File.open(@config_file) do |f|
442
+ @options = YAML.load(f)
443
+ end
444
+
445
+ case @command
446
+ when 'clone'
447
+ init_target
448
+ SatOperator.new(@options, @log).clone(@name, @new_name)
449
+ when 'destroy'
450
+ init_target
451
+ SatOperator.new(@options, @log).destroy(@sat_target)
452
+ when 'export'
453
+ init_source
454
+ SatOperator.new(@options, @log).export(@format, @sat_source, @path)
455
+ when 'extra'
456
+ init_source
457
+ init_target
458
+ SatOperator.new(@options, @log).extra(@sat_source, @sat_target)
459
+ when 'import'
460
+ init_target
461
+ SatOperator.new(@options, @log).import(@format, @sat_target, @path)
462
+ when 'sync'
463
+ init_source
464
+ init_target
465
+ SatOperator.new(@options, @log).sync(@sat_source, @sat_target)
466
+ when 'run'
467
+ def run
468
+ puts "###\nExcuting #@file_to_run\n###"
469
+ yield
470
+ end
471
+ init_source
472
+ init_target
473
+ lines=""
474
+ File.open(@file_to_run).each do |line|
475
+ lines << line
476
+ end
477
+ block=eval(lines)
478
+ run(&block)
479
+ end
480
+ rescue SystemCallError => e
481
+ @log.fatal "#{e}"
482
+ exit
483
+ ensure
484
+ # Clean-up
485
+ if @sat_source
486
+ @sat_source.terminate
487
+ end
488
+ if @sat_target
489
+ @sat_target.terminate
490
+ end
491
+ @log.info("Finished #{@command.upcase} command")
492
+ @log.close
493
+ end
494
+ end
495
+ end