promotion 1.3.0 → 1.3.1
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/CHANGELOG +1 -2
- data/lib/promotion/generator/crontab.rb +69 -0
- data/lib/promotion/generator/newsyslog.rb +51 -0
- data/lib/promotion/generator/profile.rb +43 -0
- data/lib/promotion/generator/rcconf.rb +48 -0
- data/lib/promotion/generator/sudoers.rb +55 -0
- metadata +8 -7
- data/lib/promotion/erb/crontab.erb +0 -19
- data/lib/promotion/erb/profile.erb +0 -17
- data/lib/promotion/erb/rc.conf.local.erb +0 -20
- data/lib/promotion/erb/sudoers.erb +0 -22
data/CHANGELOG
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Promotion
|
2
|
+
module Generator
|
3
|
+
module Crontab
|
4
|
+
|
5
|
+
# The crontab for each user must be deployed using the crontab tool
|
6
|
+
def self.generate(specs)
|
7
|
+
sym = "Crontab"
|
8
|
+
begin
|
9
|
+
schedules = {} # keyed on user, value is array of schedule elements
|
10
|
+
specs.each { |spec|
|
11
|
+
spec.elements.each("/Specification/Crontab/Schedule") { |sched|
|
12
|
+
user = sched.attributes["User"]
|
13
|
+
schedules[user] = [] unless schedules.has_key?(user)
|
14
|
+
schedules[user] << sched
|
15
|
+
}
|
16
|
+
}
|
17
|
+
schedules.each { |user, crontablist|
|
18
|
+
generatedContents = self.contents(user, crontablist)
|
19
|
+
userCrontab = File.expand_path(user, Folders::Crontabs)
|
20
|
+
begin
|
21
|
+
tempFilename = user + ".tmp"
|
22
|
+
tempFile = File.new(tempFilename, File::WRONLY | File::CREAT | File::TRUNC)
|
23
|
+
tempFile.puts(generatedContents)
|
24
|
+
# previous cron jobs are *NOT* preserved - the tab is competely generated!
|
25
|
+
# otherwise we accumulate the cron-generated warning messages at the top of the file
|
26
|
+
ensure
|
27
|
+
tempFile.close unless tempFile.nil? || tempFile.closed?
|
28
|
+
end
|
29
|
+
$log.info("Checking temporary crontab written to #{tempFilename}.")
|
30
|
+
crontabResults = `#{Files::Crontab} -u #{user} #{tempFilename}`
|
31
|
+
if $?.exitstatus == 0
|
32
|
+
$log.info("crontab confirms that crontab syntax is correct for user #{user}.")
|
33
|
+
else
|
34
|
+
$log.error(crontabResults)
|
35
|
+
raise
|
36
|
+
end
|
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"
|
55
|
+
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
|
+
}
|
64
|
+
return(contents.join(""))
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Promotion
|
2
|
+
module Generator
|
3
|
+
module Newsyslog
|
4
|
+
|
5
|
+
# Writes the Newsyslog configuration
|
6
|
+
def self.generate(specs)
|
7
|
+
sym = "Newsyslog"
|
8
|
+
begin
|
9
|
+
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
+
newContents = originalContents + Marker + 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\n"
|
26
|
+
specs.each { |spec|
|
27
|
+
spec.elements.each("/Specification/Newsyslog") { |nsl|
|
28
|
+
contents << "%-40s" % nsl.text()
|
29
|
+
owner = nsl.attributes["Owner"]
|
30
|
+
group = nsl.attributes["Group"]
|
31
|
+
if owner.nil? or group.nil?
|
32
|
+
og = ""
|
33
|
+
else
|
34
|
+
og = owner + ":" + group
|
35
|
+
end
|
36
|
+
contents << "%-20s" % og
|
37
|
+
contents << "%-7s" % (nsl.attributes["Mode"] || "0640")
|
38
|
+
contents << "%-7s" % (nsl.attributes["Count"] || "*")
|
39
|
+
contents << "%-7s" % (nsl.attributes["Size"] || "*")
|
40
|
+
contents << "%-9s" % (nsl.attributes["When"] || "*")
|
41
|
+
contents << "Z" if (nsl.attributes["Zip"] || "true") == "true"
|
42
|
+
contents << "B" if (nsl.attributes["Binary"] || "false") == "true"
|
43
|
+
contents << "\n"
|
44
|
+
}
|
45
|
+
}
|
46
|
+
return(contents.join(""))
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Promotion
|
2
|
+
module Generator
|
3
|
+
module Profile
|
4
|
+
|
5
|
+
# Writes the system profile
|
6
|
+
def self.generate(specs)
|
7
|
+
sym = "Profile"
|
8
|
+
begin
|
9
|
+
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
+
newContents = originalContents + Marker + 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"
|
25
|
+
specs.each { |spec|
|
26
|
+
spec.elements.each("/Specification/Environment") { |env|
|
27
|
+
env.elements.each("Variable") { |var|
|
28
|
+
t = var.cdatas.length > 0 ? var.cdatas[0].to_s() : var.text()
|
29
|
+
contents << "export #{var.attributes["Name"]}=\"#{t}\" \n"
|
30
|
+
}
|
31
|
+
env.elements.each("Alias") { |ali|
|
32
|
+
contents << "# #{ali.attributes["Comment"]}\n" if ali.attributes["Comment"]
|
33
|
+
t = ali.cdatas.length > 0 ? ali.cdatas[0].to_s() : ali.text()
|
34
|
+
contents << "alias #{ali.attributes["Name"]}='#{t}' \n"
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return(contents.join(""))
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Promotion
|
2
|
+
module Generator
|
3
|
+
module Rcconf
|
4
|
+
|
5
|
+
# Writes the system file /etc/rc.conf.local
|
6
|
+
def self.generate(specs)
|
7
|
+
sym = "Rc_conf"
|
8
|
+
begin
|
9
|
+
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
+
newContents = originalContents + Marker + 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"
|
27
|
+
daemonSpecs = specs.reject {|s| s.elements["/Specification/Daemon"].nil? }
|
28
|
+
daemonSpecs.sort!() { |a, b|
|
29
|
+
ap = a.elements["/Specification/Daemon"].attributes["Priority"].to_i || 10
|
30
|
+
bp = b.elements["/Specification/Daemon"].attributes["Priority"].to_i || 10
|
31
|
+
ap <=> bp
|
32
|
+
}
|
33
|
+
pkgScripts = []
|
34
|
+
daemonSpecs.each { |spec|
|
35
|
+
name = spec.attributes["Name"]
|
36
|
+
flags = spec.elements["/Specification/Daemon"].attributes["Flags"]
|
37
|
+
contents << "#{name}_flags=\"#{flags}\" \n"
|
38
|
+
pkgScripts << name
|
39
|
+
}
|
40
|
+
contents << "# rc.d(8) packages scripts\n"
|
41
|
+
contents << "# started in the specified order and stopped in reverse order\n"
|
42
|
+
contents << "pkg_scripts=\"#{pkgScripts.join(" ")}\" \n"
|
43
|
+
return(contents.join(""))
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Promotion
|
2
|
+
module Generator
|
3
|
+
module Sudoers
|
4
|
+
|
5
|
+
# Writes the sudoers file after testing it with visudo
|
6
|
+
def self.generate(specs)
|
7
|
+
sym = "Sudoers"
|
8
|
+
begin
|
9
|
+
originalContents = Promotion::Generator::original_contents_for(sym)
|
10
|
+
newContents = originalContents + Marker + 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"
|
40
|
+
specs.each { |spec|
|
41
|
+
spec.elements.each("/Specification/Sudoers/UserPrivilege") { |priv|
|
42
|
+
contents << "%-16s" % priv.attributes["User"]
|
43
|
+
contents << " ALL = "
|
44
|
+
contents << "(#{priv.attributes["Runas"]}) " if priv.attributes["Runas"]
|
45
|
+
pwd = (priv.attributes["Password"] || "false").downcase() == "true"
|
46
|
+
contents << (pwd ? " " : "NOPASSWD: ")
|
47
|
+
contents << "#{priv.text().strip()} \n"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return(contents.join(""))
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: promotion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 1
|
10
|
+
version: 1.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Richard Kernahan
|
@@ -65,10 +65,11 @@ files:
|
|
65
65
|
- lib/promotion/enforcer.rb
|
66
66
|
- lib/promotion/evolver.rb
|
67
67
|
- lib/promotion/generator.rb
|
68
|
-
- lib/promotion/
|
69
|
-
- lib/promotion/
|
70
|
-
- lib/promotion/
|
71
|
-
- lib/promotion/
|
68
|
+
- lib/promotion/generator/crontab.rb
|
69
|
+
- lib/promotion/generator/newsyslog.rb
|
70
|
+
- lib/promotion/generator/profile.rb
|
71
|
+
- lib/promotion/generator/rcconf.rb
|
72
|
+
- lib/promotion/generator/sudoers.rb
|
72
73
|
- .yardopts
|
73
74
|
- promotion.xsd
|
74
75
|
- CHANGELOG
|
@@ -1,19 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# /var/cron/tabs/<%= user %> - <%= user %>'s crontab
|
3
|
-
#
|
4
|
-
#minute hour mday month wday command
|
5
|
-
#
|
6
|
-
<% crontablist.each do |sched| %>
|
7
|
-
<% if sched.attributes["Comment"] %>
|
8
|
-
#______________________________
|
9
|
-
# <%= sched.attributes["Comment"] %>
|
10
|
-
<% end %>
|
11
|
-
<% minute = sched.attributes["Minute"] || "*" %>
|
12
|
-
<% hour = sched.attributes["Hour"] || "*" %>
|
13
|
-
<% mday = sched.attributes["DayOfMonth"] || "*" %>
|
14
|
-
<% month = sched.attributes["Month"] || "*" %>
|
15
|
-
<% wday = sched.attributes["DayOfWeek"] || "*" %>
|
16
|
-
<% cmd = (sched.elements["Command"].cdatas[0]).value().strip() %>
|
17
|
-
<%= minute + "\t" + hour + "\t" + mday + "\t" + month + "\t" + wday + "\t" + cmd %>
|
18
|
-
|
19
|
-
<% end %>
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# This section of the file should not be edited
|
2
|
-
# It was generated by the promotion application and will be overwritten
|
3
|
-
# when the next promotion occurs.
|
4
|
-
# The previous section will be preserved
|
5
|
-
<% @specs.each do |spec|
|
6
|
-
spec.elements.each("/Specification/Environment") do |env|
|
7
|
-
env.elements.each("Variable") do |var|
|
8
|
-
t = var.cdatas.length > 0 ? var.cdatas[0].to_s() : var.text() %>
|
9
|
-
export <%= var.attributes["Name"] %>="<%= t %>"<% end %>
|
10
|
-
<% env.elements.each("Alias") do |ali|
|
11
|
-
t = ali.cdatas.length > 0 ? ali.cdatas[0].to_s() : ali.text()
|
12
|
-
%><% if ali.attributes["Comment"] %><%= "\n# "+ali.attributes["Comment"]
|
13
|
-
%><% end %>
|
14
|
-
alias <%= ali.attributes["Name"] %>='<%= t %>' <%
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end %>
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# This section of the file is generated by the promotion application
|
2
|
-
# DO NOT EDIT THIS SECTION - your changes will be lost
|
3
|
-
# You may edit the section before the promotion marker
|
4
|
-
#______________________________
|
5
|
-
# generated application flags
|
6
|
-
<% daemonSpecs = @specs.reject {|s| s.elements["/Specification/Daemon"].nil? } %>
|
7
|
-
<% daemonSpecs.sort!() do |a, b| %>
|
8
|
-
<% ap = a.elements["/Specification/Daemon"].attributes["Priority"].to_i || 10 %>
|
9
|
-
<% bp = b.elements["/Specification/Daemon"].attributes["Priority"].to_i || 10 %>
|
10
|
-
<% ap <=> bp %>
|
11
|
-
<% end %>
|
12
|
-
<% pkgScripts = [] %>
|
13
|
-
<% daemonSpecs.each do |spec| %>
|
14
|
-
<%= spec.attributes["Name"] %>_flags="<%= spec.elements["/Specification/Daemon"].attributes["Flags"] %>"
|
15
|
-
<% pkgScripts << spec.attributes["Name"] %>
|
16
|
-
<% end %>
|
17
|
-
|
18
|
-
# rc.d(8) packages scripts
|
19
|
-
# started in the specified order and stopped in reverse order
|
20
|
-
pkg_scripts="<%= pkgScripts.join(" ") %>"
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# This section of the file should not be edited, even with visudo
|
2
|
-
# It was generated by the promotion application and will be overwritten
|
3
|
-
# when the next promotion occurs.
|
4
|
-
# The previous section will be preserved
|
5
|
-
|
6
|
-
Defaults timestamp_timeout=55
|
7
|
-
|
8
|
-
root ALL = (ALL) ALL
|
9
|
-
# people in group wheel may run all commands
|
10
|
-
%wheel ALL = (ALL) ALL
|
11
|
-
|
12
|
-
# Generated user privilege specifications
|
13
|
-
<% @specs.each do |spec| %>
|
14
|
-
<% spec.elements.each("/Specification/Sudoers/UserPrivilege") do |priv| %>
|
15
|
-
<%= sprintf('%-16s', priv.attributes["User"]) %>
|
16
|
-
<%= " ALL = " %>
|
17
|
-
<% if priv.attributes["Runas"] %>(<%= priv.attributes["Runas"] %>) <% end %>
|
18
|
-
<%= (priv.attributes["Password"] || "").downcase() == "true" ? " " : "NOPASSWD: " %>
|
19
|
-
<%= priv.text().strip() %>
|
20
|
-
|
21
|
-
<% end %>
|
22
|
-
<% end %>
|