1
2
3
4
5
6
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
require 'puppet/external/gratr/digraph'
# This class models a node configuration. It is the thing
# meant to be passed from server to client, and it contains all
# of the information in the configuration, including the resources
# and the relationships between them.
class Puppet::Node::Configuration < GRATR::Digraph
attr_accessor :name, :version
attr_reader :extraction_format
# Add classes to our class list.
def add_class(*classes)
classes.each do |klass|
@classes << klass
end
# Add the class names as tags, too.
tag(*classes)
end
def classes
@classes.dup
end
# Make sure we support the requested extraction format.
def extraction_format=(value)
unless respond_to?("extract_to_%s" % value)
raise ArgumentError, "Invalid extraction format %s" % value
end
@extraction_format = value
end
# Turn our configuration graph into whatever the client is expecting.
def extract
send("extract_to_%s" % extraction_format)
end
# Create the traditional TransBuckets and TransObjects from our configuration
# graph. This will hopefully be deprecated soon.
def extract_to_transportable
top = nil
current = nil
buckets = {}
unless main = vertices.find { |res| res.type == "class" and res.title == :main }
raise Puppet::DevError, "Could not find 'main' class; cannot generate configuration"
end
# Create a proc for examining edges, which we'll use to build our tree
# of TransBuckets and TransObjects.
bucket = nil
edges = proc do |edge|
# The sources are always non-builtins.
source, target = edge.source, edge.target
unless tmp = buckets[source.to_s]
if tmp = buckets[source.to_s] = source.to_trans
bucket = tmp
else
# This is because virtual resources return nil. If a virtual
# container resource contains realized resources, we still need to get
# to them. So, we keep a reference to the last valid bucket
# we returned and use that if the container resource is virtual.
end
end
bucket = tmp || bucket
if child = target.to_trans
unless bucket
raise "No bucket created for %s" % source
end
bucket.push child
# It's important that we keep a reference to any TransBuckets we've created, so
# we don't create multiple buckets for children.
unless target.builtin?
buckets[target.to_s] = child
end
end
end
dfs(:start => main, :examine_edge => edges)
unless main
raise Puppet::DevError, "Could not find 'main' class; cannot generate configuration"
end
# Retrive the bucket for the top-level scope and set the appropriate metadata.
unless result = buckets[main.to_s]
raise Puppet::DevError, "Did not evaluate top scope"
end
result.classes = classes
# Clear the cache to encourage the GC
buckets.clear
return result
end
def initialize(name)
super()
@name = name
@extraction_format ||= :transportable
@tags = []
@classes = []
end
# Add a tag.
def tag(*names)
names.each do |name|
name = name.to_s
@tags << name unless @tags.include?(name)
if name.include?("::")
name.split("::").each do |sub|
@tags << sub unless @tags.include?(sub)
end
end
end
nil
end
# Return the list of tags.
def tags
@tags.dup
end
end
|