promotion 1.0.7

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/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --title "Promotion" -m rdoc --main README lib/**/*.rb - README
data/CHANGELOG ADDED
File without changes
data/README ADDED
@@ -0,0 +1,256 @@
1
+ = Promotion
2
+ Promotion makes it possible to repeatedly deploy an application in a fast and
3
+ reliable way.
4
+
5
+ == Staging
6
+ A key concept is the *staging* area. It is a folder (+/var/staging+ by default)
7
+ where the files for each application are loaded into a named sub-folder (eg. +/var/staging/myapp+).
8
+ For example, a staging area may look like this:
9
+
10
+ /var
11
+ |__ staging
12
+ |__ webapp1 -- a web application
13
+ |__ monitor -- sysadmin tool to monitor availability
14
+ |__ analytics -- analytics app for admins
15
+ |__ snort -- a custom config for snort
16
+
17
+ In this example, note that we also have an area for an installed application like snort.
18
+ Although the binaries are installed through normal package installation,
19
+ you may have a lot of time and work invested in the
20
+ configuration. These files can of course be backed up and restored manually, but the purpose of
21
+ Promotion is to make deployment fast and reliable. One way to achieve that is to store your
22
+ valuable configuration files in source control, so you can reliably checkout the latest version
23
+ for deployment each and every time. So the +snort+ staging area need only hold a few configuration
24
+ files.
25
+
26
+ Aside: why not just use version control?::
27
+ The important files are spread all over the file system, so the only way to restore them all
28
+ in a single command is to make the root directory a subversion working folder, add selected
29
+ files to version control and then have <code>.svn</code> folders spread all over the place.
30
+ Moreover, you'd need to run svn as root.
31
+
32
+ == Deployment Descriptor
33
+ Each application has an XML <b>deployment descriptor</b> (eg. +/var/staging/myapp/deploy.xml+)
34
+ that describes the conditions necessary for the successful operation of the application.
35
+
36
+ The deployment descriptor describes how to move the files from staging to their correct
37
+ locations in the file system. This simple requirement unrolls into a chain of others:
38
+ - we need the folder to be there to put the file in
39
+ - the permissions need to be correct on the file and folder
40
+ - the ownerships must be set
41
+ - that means we need the necessary user accounts created
42
+ - which means we first need the right groups set up.
43
+
44
+ In addition to installing the application's files, there are system-wide configuration
45
+ files that need to be adjusted to enable an application to startup or run properly:
46
+ - /etc/profile
47
+ - /etc/rc.conf.local
48
+ - /etc/sudoers
49
+ - /var/cron/tabs/*
50
+
51
+ Promotion generates these files based on the set of all of the deployment descriptors it finds
52
+ in the staging area.
53
+
54
+ An important aspect is that a deployment is *idempotent* - you can do it as many
55
+ times as you like and the result will be the same. This means its safe to make a
56
+ small change to an application and re-deploy it in a few seconds, ready for testing.
57
+
58
+ Promotion is useful in a testing environment when changes and redeployments are frequent,
59
+ but it shines in a production environment by reducing maintenance downtime and risk.
60
+
61
+ Promotion was originally designed for use on an OpenBSD system, but is configurable enough to work
62
+ on any *nix system. Just modify the <code>promotion/config.rb</code> configuration file
63
+ to suit your system's paths.
64
+
65
+ == Installation
66
+ *WARNING*::
67
+ Promotion will makes changes to your operating system, including important system-wide files.
68
+
69
+ DO NOT USE ON A PRODUCTION SYSTEM without rigorous testing in a virtual machine first.
70
+
71
+ Create the staging area (and set permissions appropriately):
72
+
73
+ $ sudo mkdir /var/staging
74
+
75
+ Check out the promotion app into staging, and bootstrap promotion
76
+ $ sudo wget http://rubyforge.org/frs/download.php/76463/promotion-x.y.z.zip
77
+ $ sudo unzip promotion-x.y.z.zip -d promotion # creates the promotion sub-directory
78
+ $ cd promotion
79
+ $ sudo ruby bin/bootstrap
80
+ Promoting promotion...OK.
81
+ $ cd /var/staging
82
+ Now you are ready to use Promotion to deploy other applications.
83
+
84
+ == Usage
85
+ For each application you want to deploy, create its staging folder:
86
+ $ cd /var/staging
87
+ $ sudo svn checkout https://hosted/path/to/project/dist myapp
88
+ The project (or perhaps a +dist+ folder designed for deployment) is checked out into
89
+ a folder with the given name.
90
+
91
+ Now you can promote the application:
92
+ $ sudo promote myapp
93
+ Promoting myapp...OK.
94
+
95
+ If a database is involved, you can also migrate the database schema:
96
+ $ sudo evolve myapp
97
+ Evolving the database to version 1023
98
+ which will execute any new schema migration scripts. If you execute it again,
99
+ you will see:
100
+ $ sudo evolve myapp
101
+ Already at version 1023.
102
+
103
+ If you want to revert to an earlier version of the database schema:
104
+ $ sudo devolve myapp 1017
105
+ Devolving the database to version 1017
106
+ which will execute the schema migration scripts in the +devolve+ folder,
107
+ in reverse order from 1023 down to 1017.
108
+
109
+ == Deployment descriptor syntax
110
+ The deployment descriptor is typically named <code>deploy.xml</code> and placed at the top
111
+ of the application's staging folder (eg. <code>/var/staging/myapp</code>).
112
+
113
+ It's structure is described by the XML schema which can be found at
114
+ at +/var/staging/promotion/promotion.xsd+ or at
115
+ http://finalstep.com.au/schema/promotion.v100.xsd
116
+
117
+ === +Specification+
118
+ The top level element is a Specification
119
+ <?xml version="1.0" encoding="UTF-8" ?>
120
+ <Specification Name="myapp" Title="My Test App"
121
+ xmlns="http://finalstep.com.au/promotion/v100"
122
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
123
+ xsi:schemaLocation="http://finalstep.com.au/schema/promotion.v100.xsd ../promotion/promotion.xsd">
124
+ which has a +Name+ matching the staging folder it resides in (+myapp+), and a fuller +Title+.
125
+
126
+ === +Description+
127
+ A description element is the first child:
128
+ <Description>
129
+ The promotion manager ensures that the environment for an application
130
+ is set up correctly, including folder and file permissions and ownership,
131
+ startup scripts, sudoers privileges and environment variables.
132
+ </Description>
133
+
134
+ === +Groups+
135
+ The sequence is then driven by dependencies: you cannot set ownerships until you have
136
+ users, and you cannot create a user without a group, so Groups come first. Each of these
137
+ elements is optional however.
138
+ <Groups>
139
+ <Group Gid="502" Name="_mysql" />
140
+ </Groups>
141
+ This creates a group with group ID <code>502</code> and the name <code>_mysql</code>.
142
+
143
+ === +Users+
144
+ We can also create an admin and a user to run the MySQL daemon:
145
+ <Users>
146
+ <User Name="richard" Class="staff" Gecos="Richard Kernahan" Uid="1002" Gid="1002"
147
+ Home="/home/richard" Shell="/bin/ksh" Groups="wheel webadmin"/>
148
+ <User Name="_mysql" Class="daemon" Gecos="MySQL Account" Uid="502"Gid="502"
149
+ Home="/nonexistent" Shell="/sbin/nologin" />
150
+ </Users>
151
+
152
+ - +Name+, +Uid+, and +Gid+ are mandatory
153
+ - +Gecos+ defaults to the Name
154
+ - +Home+ for +richard+ defaults to +/home/richard+
155
+ - +Shell+ defaults to +/sbin/nologin+
156
+ - +Groups+ is an optional space-separated list of groups the user should be added to
157
+
158
+ === +Folders+
159
+ Before we can move files into place, we need the Folders set up:
160
+ <Folders Mode="0750" Owner="root" Group="wheel">
161
+ <Folder Owner="_mysql" Group="_mysql">/var/mysql</Folder>
162
+ <Folder>/home/myapp</Folder>
163
+ <Folder>/var/myapp</Folder>
164
+ </Folders>
165
+ You can have several +Folders+ elements, if desired. The defaults for all +Folder+
166
+ child elements may be set as attributes of the parent +Folders+ element. In this example,
167
+ all the folders will have permissions <code>rwxr-x---</code>, and ownership of <code>root:wheel</code>.
168
+ Note that the folder <code>/var/mysql</code> has a different owner and group. Any Folder can
169
+ override the default Mode, Owner, and Group.
170
+
171
+ === +Files+
172
+ Finally we can specify how to move the files into place:
173
+ <Files Owner="root" Group="wheel" Mode="0644" Source="conf">
174
+ <File>/etc/my.cnf</File>
175
+ <File>/etc/myapp.conf</File>
176
+ </Files>
177
+ <Files Owner="root" Group="wheel" Mode="0750" Source="sbin">
178
+ <File>/usr/local/sbin/up!</File>
179
+ <File>/usr/local/sbin/down!</File>
180
+ <File>/usr/local/sbin/push!</File>
181
+ </Files>
182
+
183
+ In this example, we have two sets of files. The first set is expected to be found under the +conf+
184
+ folder. Looking at the first file, we see the destination path +/etc/my.cnf+.
185
+ The source file should have the same filename +my.cnf+ and be located in the +conf+ folder.
186
+ This results in Promotion executing a command such as:
187
+
188
+ cp -f /var/staging/myapp/conf/my.cnf /etc/my.cnf
189
+
190
+ This allows a flatter, more convenient project folder structure, since the deployment descriptor maps
191
+ the files into their proper operating system locations.
192
+
193
+ As for Folders, the Files element can define the default Owner, Group and Mode for all File children.
194
+
195
+ === +Allfiles+
196
+ A convenient shorthand for copying all the files in a folder to another folder is the
197
+ +Allfiles+ element. In this example, we will copy everything from the conf folder to
198
+ the destination folder specified.
199
+ <Allfiles Group="bin" Mode="0644" Owner="root" Source="conf">/var/axonsec/conf</Allfiles>
200
+
201
+ === +Daemon+
202
+ To enable an application to startup automatically, a +Daemon+ element is needed. The name of the
203
+ startup script is expected to be <code>/etc/rc.d/myapp</code>.
204
+ <Daemon Flags="" Priority="10" User="" />
205
+
206
+ The +Flags+ attribute contains the command line options provided to the executable by
207
+ <code>/etc/rc.conf.local</code>.
208
+
209
+ The lower the +Priority+ value, the earlier that script is run (high values start later).
210
+
211
+ The +User+ is the user running the process, typically an unprivileged user named <code>_myapp</code>.
212
+ Leave blank to run the startup script as root (eg. as when dropping privileges).
213
+
214
+ === +Crontab+
215
+ Cron jobs are often needed for an application to run smoothly. Instead of creating them by hand,
216
+ you can specify each job as part of the deployment descriptor and let promotion set up the crontab
217
+ automatically.
218
+ <Crontab>
219
+ <Schedule User="root" Hour="2" Minute="7"
220
+ Comment="Backup the entire database at 2:07am each morning">
221
+ <Command><![CDATA[/usr/local/sbin/myappbak]]></Command>
222
+ </Schedule>
223
+ </Crontab>
224
+ In this example, we specify a job to be added to root's crontab, to backup the database
225
+ at 2:07am each morning. The time specification is as defined in <code>crontab(5)</code>:
226
+ - Minute
227
+ - Hour
228
+ - DayOfMonth
229
+ - Month
230
+ - DayOfWeek
231
+ The +Command+ is best wrapped safely in a CDATA section in case of XML-unsafe characters
232
+ like $.
233
+
234
+ The +Comment+ will be inserted into the final crontab file just before the job specification.
235
+
236
+ === +Database+
237
+ If the application has a database, we need to specify the path to the DBMS client command
238
+ line tool.
239
+ <Database>/usr/local/bin/mysql</Database>
240
+
241
+ If using SQLite3, a +Database+ attribute is also needed to specify the file to operate on:
242
+ <Database database="/var/myapp/data/orders.db">/usr/bin/sqlite3</Database>
243
+
244
+ == Database schema migration
245
+ Four components are required to automate database schema migration:
246
+ 1. Database migration scripts, stored in the +evolve+ and +devolve+ sub-folders
247
+ of the application's staging folder. These are normal migration scripts you might apply
248
+ manually.
249
+ 2. A <code><Database></code> element in the deployment descriptor, containing the path to
250
+ the database client command line tool. In the case of SQLite3, it also needs a <code>database</code>
251
+ attribute containing the path of the database file to operate on.
252
+ 3. Privileges to allow the user to apply the migration scripts to the database, or else
253
+ it will of course fail.
254
+ 4. Credentials for the user stored privately in <code>~/.my.cnf</code> or <code>~/.pgpass</code>
255
+ (unless using SQLite3). This allows the scripts to be executed in batch mode, without
256
+ prompting for a password.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.7
data/bin/devolve ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/local/bin/ruby -I/usr/local/
2
+ # This script devolves the database
3
+
4
+ require 'getoptlong'
5
+ #______________________
6
+ # Set usage
7
+ #
8
+ usage=<<-EOT
9
+ devolve - devolve the database schema using migration scripts
10
+ usage: sudo /usr/local/bin/devolve [--config configFilepath] appname target
11
+ where appname is the name of a folder in /var/staging containing a file deploy.xml
12
+ target integer version to devolve to
13
+ EOT
14
+ #______________________
15
+ # parse options
16
+ #
17
+ opts = GetoptLong.new(
18
+ [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ],
19
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ]
20
+ )
21
+ config = nil
22
+ configFilename = nil
23
+ opts.each do |opt, arg|
24
+ case opt
25
+ when "--config"
26
+ configFilename = arg
27
+ when "--help"
28
+ puts usage
29
+ exit 1
30
+ end
31
+ end
32
+ #______________________
33
+ # check arguments
34
+ #
35
+ if ARGV.length != 2
36
+ puts(usage)
37
+ exit 1
38
+ end
39
+ appname = ARGV[0]
40
+ targetVersion = ARGV[1].to_i()
41
+ unless targetVersion >= 1000
42
+ puts("target version must be 1000 or greater")
43
+ puts(usage)
44
+ exit 1
45
+ end
46
+ configFilename ||= "promotion/config.rb"
47
+ require(configFilename)
48
+ unless File.directory?(File.expand_path(appname, Folders::Staging))
49
+ puts("The application #{appname} was not found in the staging area #{Folders::Staging}")
50
+ puts("Aborting")
51
+ exit 1
52
+ end
53
+ #______________________
54
+ # start application
55
+ #
56
+ $stdout.flush()
57
+ require 'promotion/application'
58
+ app = Promotion::Application.new(appname)
59
+ app.devolve(targetVersion)
data/bin/evolve ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/local/bin/ruby -I/usr/local/
2
+ # This script evolves the database
3
+
4
+ require 'getoptlong'
5
+ #______________________
6
+ # Set usage
7
+ #
8
+ usage=<<-EOT
9
+ evolve - evolve the database schema using migration scripts
10
+ usage: sudo /usr/local/bin/evolve [--config configFilepath] appname [target]
11
+ where appname is the name of a folder in /var/staging containing a file deploy.xml
12
+ target is an integer version to evolve to (default is to evolve as far as possible)
13
+ EOT
14
+ #______________________
15
+ # parse options
16
+ #
17
+ opts = GetoptLong.new(
18
+ [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ],
19
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ]
20
+ )
21
+ config = nil
22
+ configFilename = nil
23
+ opts.each do |opt, arg|
24
+ case opt
25
+ when "--config"
26
+ configFilename = arg
27
+ when "--help"
28
+ puts usage
29
+ exit 1
30
+ end
31
+ end
32
+ #______________________
33
+ # check arguments
34
+ #
35
+ if ARGV.length < 1
36
+ puts(usage)
37
+ exit 1
38
+ end
39
+ appname = ARGV[0]
40
+ if ARGV.length > 1
41
+ targetVersion = ARGV[1].to_i()
42
+ unless targetVersion > 1000
43
+ puts(usage)
44
+ exit 1
45
+ end
46
+ end
47
+ configFilename ||= "promotion/config.rb"
48
+ require(configFilename)
49
+ unless File.directory?(File.expand_path(appname, Folders::Staging))
50
+ puts("The application #{appname} was not found in the staging area #{Folders::Staging}")
51
+ puts("Aborting")
52
+ exit 1
53
+ end
54
+ #______________________
55
+ # start application
56
+ #
57
+ $stdout.flush()
58
+ require 'promotion/application'
59
+ app = Promotion::Application.new(appname)
60
+ app.evolve(targetVersion)
data/bin/promote ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/local/bin/ruby -I/usr/local/
2
+ # This script starts the promotion application
3
+
4
+ #______________________
5
+ if Process.euid != 0
6
+ puts("This script must be run as root")
7
+ exit 1
8
+ end
9
+
10
+ require 'getoptlong'
11
+ #______________________
12
+ # Set usage
13
+ #
14
+ usage=<<-EOT
15
+ promotion - installer and configuration manager
16
+ usage: sudo /usr/local/bin/promotion [--config configFilepath] appname
17
+ where appname is the name of a folder under /var/staging
18
+ EOT
19
+ #______________________
20
+ # parse options
21
+ #
22
+ opts = GetoptLong.new(
23
+ [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ],
24
+ [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ],
25
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ]
26
+ )
27
+ config = nil
28
+ configFilename = nil
29
+ opts.each do |opt, arg|
30
+ case opt
31
+ when "--config"
32
+ configFilename = arg
33
+ when "--help"
34
+ puts usage
35
+ exit 1
36
+ end
37
+ end
38
+ #______________________
39
+ # check arguments
40
+ #
41
+ if ARGV.length() == 0
42
+ puts("No application to install. We will just regenerate the environment files.")
43
+ elsif ARGV.length() > 1
44
+ puts("Please specify just one application at a time.")
45
+ puts(usage)
46
+ exit 1
47
+ end
48
+ appname = ARGV[0]
49
+ unless File.directory?(File.expand_path(appname, "/var/staging"))
50
+ puts("The application #{appname} was not found in the staging area /var/staging")
51
+ puts("Aborting")
52
+ exit 1
53
+ end
54
+ #______________________
55
+ # Configure
56
+ #
57
+ configFilename ||= "promotion/config.rb"
58
+ require(configFilename)
59
+ #______________________
60
+ # start application
61
+ #
62
+ print("Promoting #{appname}...")
63
+ $stdout.flush()
64
+ require 'promotion/application'
65
+ app = Promotion::Application.new(appname)
66
+ app.promote()
67
+ puts("OK.")
data/deploy.xml ADDED
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <Specification Name="promotion" Title="Promotion Manager"
3
+ xmlns="http://finalstep.com.au/promotion/v100"
4
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
+ xsi:schemaLocation="http://finalstep.com.au/schema/promotion.v100.xsd ../promotion/promotion.xsd">
6
+ <Description>
7
+ The promotion manager ensures that the environment for an application
8
+ is set up correctly, including folder and file permissions and ownership,
9
+ startup scripts, sudoers privileges and environment variables.
10
+ </Description>
11
+ <Folders>
12
+ <Folder Mode="0770">/var/staging</Folder>
13
+ <Folder Mode="0770">/var/staging/promotion</Folder>
14
+ <Folder Clear="true">/usr/local/promotion</Folder>
15
+ <Folder>/usr/local/promotion/erb</Folder>
16
+ </Folders>
17
+ <Files Source="bin" Mode="0755">
18
+ <File>/usr/local/sbin/promote</File>
19
+ <File>/usr/local/sbin/evolve</File>
20
+ <File>/usr/local/sbin/devolve</File>
21
+ </Files>
22
+ <Files Source="lib/promotion">
23
+ <File>/usr/local/promotion/application.rb</File>
24
+ <File>/usr/local/promotion/config.rb</File>
25
+ <File>/usr/local/promotion/enforcer.rb</File>
26
+ <File>/usr/local/promotion/generator.rb</File>
27
+ <File>/usr/local/promotion/evolver.rb</File>
28
+ </Files>
29
+ <Files Source="lib/promotion/erb">
30
+ <File>/usr/local/promotion/erb/profile.erb</File>
31
+ <File>/usr/local/promotion/erb/rc.conf.local.erb</File>
32
+ <File>/usr/local/promotion/erb/sudoers.erb</File>
33
+ <File>/usr/local/promotion/erb/crontab.erb</File>
34
+ </Files>
35
+ </Specification>
@@ -0,0 +1,19 @@
1
+ #!/usr/local/bin/ruby
2
+ # Working directory is the ext/promotion/ folder
3
+
4
+ # generate Makefile to install binaries
5
+ source = "../../bin"
6
+ target = "/usr/local"
7
+ makeContents=<<-EOT
8
+ # Makefile for Promotion
9
+ .PHONY : all
10
+ all :
11
+ .PHONY : install
12
+ install :
13
+ install -m 0750 -o root -g wheel #{source}/promote #{target}/sbin
14
+ install -m 0750 -o root -g wheel #{source}/evolve #{target}/sbin
15
+ install -m 0750 -o root -g wheel #{source}/devolve #{target}/sbin
16
+ EOT
17
+ makefile = File.new("Makefile", "w")
18
+ makefile.puts(makeContents)
19
+ makefile.close()
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'promotion/enforcer'
3
+ require 'promotion/generator'
4
+ require 'promotion/evolver'
5
+ require 'log4r'
6
+ include Log4r
7
+
8
+ module Promotion # :nodoc:
9
+
10
+ # The Promotion::Application coordinates the activity of the components:
11
+ # - Enforcer
12
+ # - Generator
13
+ # - Evolver
14
+ class Application
15
+
16
+ # Creates a new Promotion::Application instance for a specific app to be promoted.
17
+ # A global +$log+ logger is also created.
18
+ def initialize(appname)
19
+ @appname = appname
20
+ $log = Logger.new(@appname)
21
+ FileOutputter[@appname] = FileOutputter.new(@appname, :filename => Files::Log)
22
+ FileOutputter[@appname].formatter = PatternFormatter.new(:pattern => "%d %m")
23
+ $log.outputters = FileOutputter[@appname]
24
+ end
25
+
26
+ # Promotes an application into production.
27
+ def promote()
28
+ enforcer = Promotion::Enforcer.new(@appname)
29
+ generator = Promotion::Generator.new()
30
+ enforcer.start()
31
+ generator.start()
32
+ $log.info("Application #{@appname} successfully promoted.")
33
+ end
34
+
35
+ # Evolves the database to a target version, or as far as possible, by
36
+ # executing database migration scripts in the +evolve+ folder
37
+ def evolve(target=nil)
38
+ evolver = Promotion::Evolver.new(@appname, true, target)
39
+ evolver.start()
40
+ end
41
+
42
+ # Devolve a database back to an earlier version
43
+ def devolve(target=nil)
44
+ evolver = Promotion::Evolver.new(@appname, false, target)
45
+ evolver.start()
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,55 @@
1
+ # application configuration for promotion
2
+ # PRODUCTION
3
+
4
+ # A section of the configuration file that contains folder paths
5
+ module Folders
6
+ # The folder where applications are staged (eg. from Subversion)
7
+ # ready for deployment
8
+ Staging = "/var/staging"
9
+ # The folder containing the ERB templates
10
+ Templates = "/usr/local/promotion/erb"
11
+ # The system crontab folder
12
+ Crontabs = "/var/cron/tabs"
13
+ end
14
+
15
+ # A section of the configuration file that contains file paths
16
+ module Files
17
+ # The standard name of the deployment descriptor for all apps
18
+ Spec = "deploy.xml"
19
+ # The log file for promotion
20
+ Log = "/var/staging/Promotion.log"
21
+ # system path to the shared profile
22
+ Profile = "/etc/profile"
23
+ # system path to the sudoers file
24
+ Sudoers = "/etc/sudoers"
25
+ # system path to rc.conf.local
26
+ Rc_conf = "/etc/rc.conf.local"
27
+ # path to useradd executable
28
+ Useradd = "/usr/sbin/useradd"
29
+ # path to groupadd executable
30
+ Groupadd = "/usr/sbin/groupadd"
31
+ # path to visudo executable
32
+ Visudo = "/usr/sbin/visudo"
33
+ # path to crontab executable
34
+ Crontab = "/usr/bin/crontab"
35
+ # path to zip executable
36
+ Zip = "/usr/local/bin/zip -q "
37
+ end
38
+
39
+ # A section of the configuration file that contains ERB template filenames
40
+ module Templates
41
+ # filename for Profile template
42
+ Profile = "profile.erb"
43
+ # filename for Rc_conf template
44
+ Rc_conf = "rc.conf.local.erb"
45
+ # filename for Sudoers template
46
+ Sudoers = "sudoers.erb"
47
+ # filename for Crontab template
48
+ Crontab = "crontab.erb"
49
+ end
50
+
51
+ raise "staging area not found" unless File.directory?(Folders::Staging)
52
+ raise "template folder not found" unless File.directory?(Folders::Templates)
53
+ Templates.constants { |template|
54
+ raise "template #{template} not found" unless File.exist?(File.expand_path(Templates.const_get(template), Folders::Templates))
55
+ }