promotion 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|