promotion 1.4.7 → 2.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.
- checksums.yaml +7 -0
- data/CHANGELOG +5 -0
- data/README +7 -11
- data/lib/promotion/application.rb +7 -6
- data/lib/promotion/generator/crontab.rb +31 -57
- data/lib/promotion/generator/newsyslog.rb +20 -33
- data/lib/promotion/generator/profile.rb +12 -22
- data/lib/promotion/generator/rcconf.rb +14 -27
- data/lib/promotion/generator/sudoers.rb +12 -40
- data/lib/promotion/generator.rb +6 -32
- metadata +43 -75
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 108a5dc05ae4bb258ba20b5b00a77707a4031176
|
4
|
+
data.tar.gz: c5a25b54336e9b6f5247cbda54812da242c3f7a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9497b89f2b3b4805d7db3f60fa64ee439475ad7e1f95b229876ecc94d3a120b02dda71c1a10fcfadd231b8620e5dc5af9c07634d23ec3b67dfdee68df74e6867
|
7
|
+
data.tar.gz: baa82d045a06c70f4118678baab14f6c6170f2209c76b441f6c2ae66dbaf91af90f57aebf578d12de1140b71740c162066a4120a7cc990fa7964d589301032fa
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
== Version 2.0
|
2
|
+
- Promotion no longer changes the system-wide files, such as /etc/rc.conf.local. Instead it just recommends what should be changed.
|
3
|
+
- Upgraded for Ruby 2.0, since 1.8.7 is no longer supported.
|
4
|
+
- Removed the log4r dependency in favour of the standard library Logger.
|
5
|
+
|
1
6
|
== Version 1.4.7
|
2
7
|
- Preserve empty lines in config files
|
3
8
|
|
data/README
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
= Promotion
|
2
|
-
Promotion makes it possible to repeatedly deploy an application in a fast and
|
3
|
-
reliable way.
|
2
|
+
Promotion makes it possible to repeatedly deploy an application in a fast and reliable way.
|
4
3
|
|
5
4
|
== Staging
|
6
5
|
A key concept is the *staging* area. It is a folder (+/var/staging+ by default)
|
@@ -48,11 +47,10 @@ files that need to be adjusted to enable an application to startup or run proper
|
|
48
47
|
- /etc/sudoers
|
49
48
|
- /var/cron/tabs/*
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
This respects the need for an administrator to add custom contents (above the line).
|
50
|
+
Deployment descriptors can include recommended settings for these sensitive system files, but it
|
51
|
+
does not change them. That would be too intrusive. Instead, Promotion reads the files to check if the
|
52
|
+
recommended entries are present, and if they are not it displays a message for the admin explaining
|
53
|
+
what needs to be done.
|
56
54
|
|
57
55
|
An important aspect is that a deployment is *idempotent* - you can do it as many
|
58
56
|
times as you like and the result will be the same. This means its safe to make a
|
@@ -67,7 +65,7 @@ to suit your system's paths.
|
|
67
65
|
|
68
66
|
== Installation
|
69
67
|
*WARNING*::
|
70
|
-
Promotion will makes changes to your operating system
|
68
|
+
Promotion will makes changes to your operating system.
|
71
69
|
|
72
70
|
DO NOT USE ON A PRODUCTION SYSTEM without rigorous testing in a virtual machine first.
|
73
71
|
|
@@ -235,9 +233,7 @@ The +User+ is the user running the process, typically an unprivileged user named
|
|
235
233
|
Leave blank to run the startup script as root (eg. as when dropping privileges).
|
236
234
|
|
237
235
|
=== +Crontab+
|
238
|
-
Cron jobs are often needed for an application to run smoothly.
|
239
|
-
you can specify each job as part of the deployment descriptor and let promotion set up the crontab
|
240
|
-
automatically.
|
236
|
+
Cron jobs are often needed for an application to run smoothly.
|
241
237
|
<Crontab>
|
242
238
|
<Schedule User="root" Hour="2" Minute="7"
|
243
239
|
Comment="Backup the entire database at 2:07am each morning">
|
@@ -3,8 +3,8 @@ require 'promotion/config'
|
|
3
3
|
require 'promotion/enforcer'
|
4
4
|
require 'promotion/generator'
|
5
5
|
require 'promotion/evolver'
|
6
|
-
require '
|
7
|
-
|
6
|
+
require 'logger'
|
7
|
+
require 'time'
|
8
8
|
|
9
9
|
module Promotion # :nodoc:
|
10
10
|
|
@@ -18,10 +18,11 @@ class Application
|
|
18
18
|
# A global +$log+ logger is also created.
|
19
19
|
def initialize(appname)
|
20
20
|
@appname = appname
|
21
|
-
$log = Logger.new(
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
$log = Logger.new(Files::Log, 0) # rotate log file at 1M limit
|
22
|
+
$log.formatter = proc { |severity, datetime, progname, message|
|
23
|
+
"#{datetime.iso8601()} #{severity} #{message}\n"
|
24
|
+
}
|
25
|
+
$log.level = Logger::INFO
|
25
26
|
end
|
26
27
|
|
27
28
|
# Promotes an application into production.
|
@@ -3,65 +3,39 @@ module Generator
|
|
3
3
|
module Crontab
|
4
4
|
|
5
5
|
# The crontab for each user must be deployed using the crontab tool
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
FileUtils.rm_f(tempFilename)
|
38
|
-
$log.info("New crontab installed for user #{user}")
|
39
|
-
}
|
40
|
-
rescue => e
|
41
|
-
$log.error("Error occurred while generating crontab\n#{e.message}" + e.backtrace.join("\n"))
|
42
|
-
exit 1
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Generates the contents for /var/cron/tabs/{user}, containing scheduled jobs
|
47
|
-
def self.contents(user, crontablist)
|
48
|
-
contents = []
|
49
|
-
contents << "# /var/cron/tabs/#{user} - #{user}'s crontab \n#\n"
|
50
|
-
contents << "#minute hour mday month wday command\n#\n\n"
|
51
|
-
crontablist.each { |sched|
|
52
|
-
if sched.attributes["Comment"]
|
53
|
-
contents << "#______________________________\n"
|
54
|
-
contents << "# #{sched.attributes["Comment"]} \n"
|
6
|
+
def self.check(specs)
|
7
|
+
schedules = {} # keyed on user, value is array of schedule elements
|
8
|
+
specs.each { |spec|
|
9
|
+
spec.elements.each("/Specification/Crontab/Schedule") { |sched|
|
10
|
+
user = sched.attributes["User"]
|
11
|
+
schedules[user] = [] unless schedules.has_key?(user)
|
12
|
+
schedules[user] << sched
|
13
|
+
}
|
14
|
+
}
|
15
|
+
schedules.each { |user, crontablist|
|
16
|
+
userCrontab = File.expand_path(user, "/var/cron/tabs/")
|
17
|
+
contents = IO.readlines(userCrontab).collect!{ |s| s.gsub(/\s/,"") }
|
18
|
+
proposals = []
|
19
|
+
crontablist.each { |sched|
|
20
|
+
minute = sched.attributes["Minute"] || "*"
|
21
|
+
hour = sched.attributes["Hour"] || "*"
|
22
|
+
mday = sched.attributes["DayOfMonth"] || "*"
|
23
|
+
month = sched.attributes["Month"] || "*"
|
24
|
+
wday = sched.attributes["DayOfWeek"] || "*"
|
25
|
+
cmd = (sched.elements["Command"].cdatas[0]).value().strip()
|
26
|
+
needed = minute + "\t" + hour + "\t" + mday + "\t" + month + "\t" + wday + "\t" + cmd
|
27
|
+
unless contents.include?(needed.gsub(/\s/,""))
|
28
|
+
if sched.attributes["Comment"]
|
29
|
+
proposals << "# #{sched.attributes["Comment"]}"
|
30
|
+
end
|
31
|
+
proposals << needed
|
32
|
+
end
|
33
|
+
}
|
34
|
+
if proposals.size > 0
|
35
|
+
header = "# min\thour\tmday\tmonth\twday\tcommand\n"
|
36
|
+
puts("\nSuggested changes to /var/cron/tabs/#{user}:", header, proposals.join("\n"), "\n")
|
55
37
|
end
|
56
|
-
minute = sched.attributes["Minute"] || "*"
|
57
|
-
hour = sched.attributes["Hour"] || "*"
|
58
|
-
mday = sched.attributes["DayOfMonth"] || "*"
|
59
|
-
month = sched.attributes["Month"] || "*"
|
60
|
-
wday = sched.attributes["DayOfWeek"] || "*"
|
61
|
-
cmd = (sched.elements["Command"].cdatas[0]).value().strip()
|
62
|
-
contents << minute + "\t" + hour + "\t" + mday + "\t" + month + "\t" + wday + "\t" + cmd + "\n"
|
63
38
|
}
|
64
|
-
return(contents.join(""))
|
65
39
|
end
|
66
40
|
|
67
41
|
end
|
@@ -3,29 +3,12 @@ module Generator
|
|
3
3
|
module Newsyslog
|
4
4
|
|
5
5
|
# Writes the Newsyslog configuration
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
-
newContents = originalContents + Marker + "\n" + contents(specs)
|
11
|
-
Promotion::Generator::write_file_for(sym, newContents)
|
12
|
-
rescue => e
|
13
|
-
$log.error("Error occurred while generating #{sym}\n#{e.message}" + e.backtrace.join("\n"))
|
14
|
-
exit 1
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Generates the contents for /etc/newsyslog.conf, which controls rolling and retention of logs
|
19
|
-
def self.contents(specs)
|
20
|
-
contents = []
|
21
|
-
contents << "# This section of the file should not be edited\n"
|
22
|
-
contents << "# It was generated by the promotion application and will be overwritten\n"
|
23
|
-
contents << "# when the next promotion occurs.\n"
|
24
|
-
contents << "# The previous section will be preserved\n\n"
|
25
|
-
contents << "# Filename Owner:Group Mode Count Size When Flags Command\n"
|
6
|
+
def self.check(specs)
|
7
|
+
contents = IO.readlines("/etc/newsyslog.conf").collect!{ |s| s.gsub(/\s/,"") }
|
8
|
+
proposals = []
|
26
9
|
specs.each { |spec|
|
27
10
|
spec.elements.each("/Specification/Newsyslog") { |nsl|
|
28
|
-
|
11
|
+
needed = nsl.text() << "\t"
|
29
12
|
owner = nsl.attributes["Owner"]
|
30
13
|
group = nsl.attributes["Group"]
|
31
14
|
if owner.nil? or group.nil?
|
@@ -33,31 +16,35 @@ module Newsyslog
|
|
33
16
|
else
|
34
17
|
og = owner + ":" + group
|
35
18
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
19
|
+
needed << og << "\t"
|
20
|
+
needed << (nsl.attributes["Mode"] || "0640") << "\t"
|
21
|
+
needed << (nsl.attributes["Count"] || "*") << "\t"
|
22
|
+
needed << (nsl.attributes["Size"] || "*") << "\t"
|
40
23
|
# treat as $-format if starts with D,W,M; treat as integer if integer
|
41
24
|
# else treat as @-format if digits with a 'T'
|
42
25
|
sched = nsl.attributes["When"] || "*"
|
43
26
|
if sched[0..0] == "D" or sched[0..0] == "W" or sched[0..0] == "M"
|
44
|
-
|
27
|
+
needed << sched << "\t"
|
45
28
|
elsif sched.include?("T")
|
46
|
-
|
29
|
+
needed << "@" << sched << "\t"
|
47
30
|
else
|
48
|
-
|
31
|
+
needed << sched << "\t"
|
49
32
|
end
|
50
33
|
# We normally do not want to add rotation messages or compress
|
51
|
-
|
52
|
-
|
34
|
+
needed << "Z" if (nsl.attributes["Zip"] || "false") == "true"
|
35
|
+
needed << "B" if (nsl.attributes["Binary"] || "true") == "true"
|
53
36
|
restart = nsl.attributes["Restart"] # service to restart
|
54
37
|
if restart
|
55
|
-
|
38
|
+
needed << "\t/etc/rc.d/#{restart} restart >/dev/null 2>&1 "
|
56
39
|
end
|
57
|
-
|
40
|
+
# see if its already present - check the pattern ignoring whitespace
|
41
|
+
proposals << needed unless contents.include?(needed.gsub(/\s/,""))
|
58
42
|
}
|
59
43
|
}
|
60
|
-
|
44
|
+
if proposals.size > 0
|
45
|
+
header = "# Filename\t\tOwner:Group\tMode\tCount\tSize\tWhen\tFlags\tCommand\n"
|
46
|
+
puts("\nSuggested changes to /etc/newsyslog.conf:", header, proposals.join("\n"), "\n")
|
47
|
+
end
|
61
48
|
end
|
62
49
|
|
63
50
|
end
|
@@ -3,39 +3,29 @@ module Generator
|
|
3
3
|
module Profile
|
4
4
|
|
5
5
|
# Writes the system profile
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
-
newContents = originalContents + Marker + "\n" + contents(specs)
|
11
|
-
Promotion::Generator::write_file_for(sym, newContents)
|
12
|
-
rescue => e
|
13
|
-
$log.error("Error occurred while generating #{sym}\n#{e.message}" + e.backtrace.join("\n"))
|
14
|
-
exit 1
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Generates the contents for /etc/profile, containing environment variables and aliases
|
19
|
-
def self.contents(specs)
|
20
|
-
contents = []
|
21
|
-
contents << "# This section of the file should not be edited\n"
|
22
|
-
contents << "# It was generated by the promotion application and will be overwritten\n"
|
23
|
-
contents << "# when the next promotion occurs.\n"
|
24
|
-
contents << "# The previous section will be preserved\n"
|
6
|
+
def self.check(specs)
|
7
|
+
contents = IO.readlines("/etc/profile").collect!{ |s| s.strip() }
|
8
|
+
proposals = []
|
25
9
|
specs.each { |spec|
|
26
10
|
spec.elements.each("/Specification/Environment") { |env|
|
27
11
|
env.elements.each("Variable") { |var|
|
28
12
|
t = var.cdatas.length > 0 ? var.cdatas[0].to_s() : var.text()
|
29
|
-
|
13
|
+
needed = "export #{var.attributes["Name"]}=\"#{t}\""
|
14
|
+
unless contents.include?(needed.strip())
|
15
|
+
proposals << needed
|
16
|
+
end
|
30
17
|
}
|
31
18
|
env.elements.each("Alias") { |ali|
|
32
19
|
contents << "# #{ali.attributes["Comment"]}\n" if ali.attributes["Comment"]
|
33
20
|
t = ali.cdatas.length > 0 ? ali.cdatas[0].to_s() : ali.text()
|
34
|
-
|
21
|
+
needed = "alias #{ali.attributes["Name"]}='#{t}'"
|
22
|
+
unless contents.include?(needed.strip())
|
23
|
+
proposals << needed
|
24
|
+
end
|
35
25
|
}
|
36
26
|
}
|
37
27
|
}
|
38
|
-
|
28
|
+
puts("\nSuggested changes to /etc/profile:", proposals.join("\n"), "\n") if proposals.size > 0
|
39
29
|
end
|
40
30
|
|
41
31
|
end
|
@@ -3,27 +3,10 @@ module Generator
|
|
3
3
|
module Rcconf
|
4
4
|
|
5
5
|
# Writes the system file /etc/rc.conf.local
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
newContents = originalContents + Marker + "\n" + contents(specs)
|
11
|
-
Promotion::Generator::write_file_for(sym, newContents)
|
12
|
-
rescue => e
|
13
|
-
$log.error("Error occurred while generating #{sym}\n#{e.message}" + e.backtrace.join("\n"))
|
14
|
-
exit 1
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Generates the contents for /etc/rc.conf.local, containing instructions for running daemons
|
19
|
-
def self.contents(specs)
|
20
|
-
contents = []
|
21
|
-
contents << "# This section of the file should not be edited\n"
|
22
|
-
contents << "# It was generated by the promotion application and will be overwritten\n"
|
23
|
-
contents << "# when the next promotion occurs.\n"
|
24
|
-
contents << "# The previous section will be preserved\n"
|
25
|
-
contents << "# ---------------------------\n"
|
26
|
-
contents << "# generated application flags\n"
|
6
|
+
def self.check(specs)
|
7
|
+
contents = IO.readlines("/etc/rc.conf.local").collect!{ |s| s.strip() }
|
8
|
+
proposals = []
|
9
|
+
# Extract package scripts and sort them by increasing priority
|
27
10
|
daemonSpecs = specs.reject {|s| s.elements["/Specification/Daemon"].nil? }
|
28
11
|
daemonSpecs.sort!() { |a, b|
|
29
12
|
ap = a.elements["/Specification/Daemon"].attributes["Priority"].to_i || 10
|
@@ -31,18 +14,22 @@ module Rcconf
|
|
31
14
|
ap <=> bp
|
32
15
|
}
|
33
16
|
pkgScripts = []
|
34
|
-
daemonSpecs.each { |spec|
|
35
|
-
spec.each_element("Daemon") { |d|
|
17
|
+
daemonSpecs.each { |spec|
|
18
|
+
spec.each_element("Daemon") { |d| # allow for multiple daemons in a spec
|
36
19
|
# Name defaults to the name of the spec, but may be overridden by the optional Name attribute
|
37
20
|
name = d.attributes["Name"] || spec.attributes["Name"]
|
38
21
|
flags = d.attributes["Flags"]
|
39
|
-
|
22
|
+
needed = "#{name}_flags=\"#{flags}\""
|
23
|
+
proposals << needed unless contents.include?(needed.strip())
|
40
24
|
pkgScripts << name
|
41
25
|
}
|
42
26
|
}
|
43
|
-
|
44
|
-
|
45
|
-
|
27
|
+
puts("\nSuggested changes to /etc/rc.conf.local:", proposals.join("\n")) if proposals.size > 0
|
28
|
+
pkgList = pkgScripts.join(" ")
|
29
|
+
unless contents.join("\n") =~ /pkg_scripts.*#{pkgList}/
|
30
|
+
puts("pkg_scripts=\"${pkg_scripts} #{pkgList}\" ")
|
31
|
+
end
|
32
|
+
puts("") if proposals.size > 0
|
46
33
|
end
|
47
34
|
|
48
35
|
end
|
@@ -3,51 +3,23 @@ module Generator
|
|
3
3
|
module Sudoers
|
4
4
|
|
5
5
|
# Writes the sudoers file after testing it with visudo
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
-
newContents = originalContents + Marker + "\n" + contents(specs)
|
11
|
-
tempFilename = Promotion::Generator::write_file_for(sym, newContents, true)
|
12
|
-
$log.info("Checking temporary sudoers written to #{tempFilename}.")
|
13
|
-
visudoResults = `#{Files::Visudo} -c -f #{tempFilename}`
|
14
|
-
if visudoResults =~ /parsed OK/
|
15
|
-
$log.info("visudo confirms that sudoers syntax is correct.")
|
16
|
-
else
|
17
|
-
$log.error(visudoResults)
|
18
|
-
raise
|
19
|
-
end
|
20
|
-
Promotion::Generator::write_file_for("Sudoers", newContents)
|
21
|
-
FileUtils.rm_f(tempFilename)
|
22
|
-
rescue => e
|
23
|
-
$log.error("Error occurred while generating sudoers\n#{e.message}" + e.backtrace.join("\n"))
|
24
|
-
exit 1
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Generates the contents for /etc/sudoers, containing environment variables and aliases
|
29
|
-
def self.contents(specs)
|
30
|
-
contents = []
|
31
|
-
contents << "# This section of the file should not be edited\n"
|
32
|
-
contents << "# It was generated by the promotion application and will be overwritten\n"
|
33
|
-
contents << "# when the next promotion occurs.\n"
|
34
|
-
contents << "# The previous section will be preserved\n\n"
|
35
|
-
contents << "Defaults timestamp_timeout=55\n\n"
|
36
|
-
contents << "root ALL = (ALL) ALL \n"
|
37
|
-
contents << "# people in group wheel may run all commands \n"
|
38
|
-
contents << "%wheel ALL = (ALL) ALL \n\n"
|
39
|
-
contents << "# Generated user privilege specifications \n"
|
6
|
+
def self.check(specs)
|
7
|
+
contents = IO.readlines("/etc/sudoers").collect!{ |s| s.strip() }
|
8
|
+
proposals = []
|
40
9
|
specs.each { |spec|
|
41
10
|
spec.elements.each("/Specification/Sudoers/UserPrivilege") { |priv|
|
42
|
-
|
43
|
-
|
44
|
-
|
11
|
+
needed = "%-16s" % priv.attributes["User"]
|
12
|
+
needed << " ALL = "
|
13
|
+
needed << "(#{priv.attributes["Runas"]}) " if priv.attributes["Runas"]
|
45
14
|
pwd = (priv.attributes["Password"] || "false").downcase() == "true"
|
46
|
-
|
47
|
-
|
15
|
+
needed << (pwd ? " " : "NOPASSWD: ")
|
16
|
+
needed << "#{priv.text().strip()}"
|
17
|
+
proposals << needed unless contents.include?(needed.strip())
|
48
18
|
}
|
49
19
|
}
|
50
|
-
|
20
|
+
if proposals.size > 0
|
21
|
+
puts("\nSuggested changes to /etc/sudoers:", proposals.join("\n"), "\n") if proposals.size > 0
|
22
|
+
end
|
51
23
|
end
|
52
24
|
|
53
25
|
end
|
data/lib/promotion/generator.rb
CHANGED
@@ -8,16 +8,14 @@ require 'promotion/generator/crontab'
|
|
8
8
|
module Promotion
|
9
9
|
module Generator
|
10
10
|
|
11
|
-
Marker = "#---promotion---" # add this marker to a config file to preserve the contents before it
|
12
|
-
|
13
11
|
def self.start()
|
14
|
-
$log.info("\n#{'_'*40}\
|
12
|
+
$log.info("\n#{'_'*40}\nChecking common environment files")
|
15
13
|
specs = self.gather_specs()
|
16
|
-
Profile.
|
17
|
-
Rcconf.
|
18
|
-
Newsyslog.
|
19
|
-
Sudoers.
|
20
|
-
Crontab.
|
14
|
+
Profile.check(specs)
|
15
|
+
Rcconf.check(specs)
|
16
|
+
Newsyslog.check(specs)
|
17
|
+
Sudoers.check(specs)
|
18
|
+
Crontab.check(specs)
|
21
19
|
end
|
22
20
|
|
23
21
|
# Gathers specs from all deployment descriptors in folders with the staging area
|
@@ -40,29 +38,5 @@ module Generator
|
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
43
|
-
# Write the approved contents to the system file
|
44
|
-
# or a temporary file instead if temp is true.
|
45
|
-
def self.write_file_for(sym, newContents, temp=false)
|
46
|
-
begin
|
47
|
-
filename = Files.const_get(sym) + (temp ? ".tmp" : "")
|
48
|
-
f = File.new(filename, File::WRONLY | File::CREAT | File::TRUNC)
|
49
|
-
f.puts(newContents)
|
50
|
-
$log.info("Generated #{sym} written to #{filename}.") unless temp
|
51
|
-
ensure
|
52
|
-
f.close unless f.nil? || f.closed?
|
53
|
-
end
|
54
|
-
return(filename)
|
55
|
-
end
|
56
|
-
|
57
|
-
# Returns a string of the new content for the file up to the +marker+
|
58
|
-
def self.original_contents_for(sym)
|
59
|
-
begin
|
60
|
-
originalContents = IO.readlines(Files.const_get(sym), nil)[0].split(Marker)[0]
|
61
|
-
rescue
|
62
|
-
originalContents = ""
|
63
|
-
end
|
64
|
-
return(originalContents)
|
65
|
-
end
|
66
|
-
|
67
41
|
end
|
68
42
|
end
|
metadata
CHANGED
@@ -1,59 +1,36 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: promotion
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 4
|
9
|
-
- 7
|
10
|
-
version: 1.4.7
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '2.0'
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Richard Kernahan
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
type: :runtime
|
35
|
-
version_requirements: *id001
|
36
|
-
description: "\t\tThe Promotion tool is designed to make it easy and quick to deploy an application\n\
|
37
|
-
\t\tinto production. Originally built for use with OpenBSD, it can be used on an *nix\n\
|
38
|
-
\t\tsystem by adjusting a few paths (in config.rb).\n\n\
|
39
|
-
\t\tTo deploy or install an application you just need to copy a few files into place, right?\n\
|
40
|
-
\t\tWell, the folders need to be there first of course, oh and the permissions need to be set,\n\
|
41
|
-
\t\tand I guess we need the right users set up before file ownerships can be set correctly,\n\
|
42
|
-
\t\twhich means we need groups before that ... ok, so there is more to it than copying a few files.\n\n\
|
43
|
-
\t\tThere are also system-wide settings that may need to be modified to support an application,\n\
|
44
|
-
\t\tsuch as environment variables in /etc/profile, /etc/sudoers,\n\
|
45
|
-
\t\tstartup scripts in /etc/rc.conf.local, and /var/cron/tabs/* cron jobs.\n\n\
|
46
|
-
\t\tPromotion handles all of this based on an XML deployment descriptor for each application,\n\
|
47
|
-
\t\tallowing rapid, reliable redeployment with a single line command. It also manages database\n\
|
48
|
-
\t\tschema migration.\n"
|
11
|
+
date: 2013-10-30 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: "\t\tThe Promotion tool is designed to make it easy and quick to deploy
|
14
|
+
an application\n\t\tinto production. Originally built for use with OpenBSD, it can
|
15
|
+
be used on an *nix\n\t\tsystem by adjusting a few paths (in config.rb).\n\n\t\tTo
|
16
|
+
deploy or install an application you just need to copy a few files into place, right?\n\t\tWell,
|
17
|
+
the folders need to be there first of course, oh and the permissions need to be
|
18
|
+
set,\n\t\tand I guess we need the right users set up before file ownerships can
|
19
|
+
be set correctly,\n\t\twhich means we need groups before that ... ok, so there is
|
20
|
+
more to it than copying a few files.\n\n\t\tThere are also system-wide settings
|
21
|
+
that may need to be modified to support an application,\n\t\tsuch as environment
|
22
|
+
variables in /etc/profile, /etc/sudoers,\n\t\tstartup scripts in /etc/rc.conf.local,
|
23
|
+
and /var/cron/tabs/* cron jobs.\n\t\tPromotion does not modify these sensitive files,
|
24
|
+
but it does say what's missing or needs to be changed.\n\n\t\tPromotion handles
|
25
|
+
all of this based on an XML deployment descriptor for each application,\n\t\tallowing
|
26
|
+
rapid, reliable redeployment with a single line command. It also manages database\n\t\tschema
|
27
|
+
migration.\n"
|
49
28
|
email: dev.promotion@finalstep.com.au
|
50
29
|
executables: []
|
51
|
-
|
52
30
|
extensions: []
|
53
|
-
|
54
|
-
extra_rdoc_files:
|
31
|
+
extra_rdoc_files:
|
55
32
|
- README
|
56
|
-
files:
|
33
|
+
files:
|
57
34
|
- bin/promote
|
58
35
|
- bin/evolve
|
59
36
|
- bin/devolve
|
@@ -76,41 +53,32 @@ files:
|
|
76
53
|
- README
|
77
54
|
homepage: http://rubygems.org/gems/promotion
|
78
55
|
licenses: []
|
79
|
-
|
80
|
-
post_install_message: "\n\n To install the executables (promote, evolve, devolve,
|
81
|
-
\t$ sudo ruby -rubygems -e \"require
|
82
|
-
|
56
|
+
metadata: {}
|
57
|
+
post_install_message: "\n\n To install the executables (promote, evolve, devolve,
|
58
|
+
mkdeploy)\n issue the following command:\n\t$ sudo ruby -rubygems -e \"require
|
59
|
+
'promotion/install'\"\n\n "
|
60
|
+
rdoc_options:
|
83
61
|
- --title
|
84
62
|
- Promotion
|
85
63
|
- --main
|
86
64
|
- README
|
87
|
-
require_paths:
|
65
|
+
require_paths:
|
88
66
|
- lib
|
89
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
none: false
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
hash: 3
|
104
|
-
segments:
|
105
|
-
- 0
|
106
|
-
version: "0"
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
107
77
|
requirements: []
|
108
|
-
|
109
78
|
rubyforge_project: promotion
|
110
|
-
rubygems_version:
|
79
|
+
rubygems_version: 2.0.3
|
111
80
|
signing_key:
|
112
|
-
specification_version:
|
113
|
-
summary: Promotion makes it possible to repeatedly deploy an application in a fast
|
81
|
+
specification_version: 4
|
82
|
+
summary: Promotion makes it possible to repeatedly deploy an application in a fast
|
83
|
+
and reliable way.
|
114
84
|
test_files: []
|
115
|
-
|
116
|
-
has_rdoc: "true"
|