Class: Cult::Node

Inherits:
Role
  • Object
show all
Defined in:
lib/cult/node.rb

Class Attribute Summary collapse

Attributes inherited from Role

#path, #project

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Role

#==, all, all_files, #artifacts, #build_order, #build_tasks, by_name, #collection_name, #definition, #definition_parents, delegate_to_definition, #event_tasks, #has_role?, #hash, #initialize, #inspect, #name, #names_for_role, #names_for_task, #parent_roles, #query_for_role, #recursive_parent_roles, #relative_path, #remote_path, #role_file, #tasks, #tree

Methods included from SingletonInstances

included

Constructor Details

This class inherits a constructor from Cult::Role

Class Attribute Details

.marshal_excludeObject

Returns the value of attribute marshal_exclude.



10
11
12
# File 'lib/cult/node.rb', line 10

def marshal_exclude
  @marshal_exclude
end

Class Method Details

.from_data!(project, data) ⇒ Object

Raises:

  • (Errno::EEXIST)


32
33
34
35
36
37
38
39
40
41
42
# File 'lib/cult/node.rb', line 32

def self.from_data!(project, data)
  node = by_name(project, data[:name])
  raise Errno::EEXIST if node.exist?

  FileUtils.mkdir_p(node.path)
  File.write(node.node_path, JSON.pretty_generate(data))

  node.generate_ssh_keys!

  return by_name(project, data[:name])
end

.path(project) ⇒ Object



60
61
62
# File 'lib/cult/node.rb', line 60

def self.path(project)
  File.join(project.path, 'nodes')
end

Instance Method Details

#addr(access, protocol = project.default_ip_protocol) ⇒ Object



144
145
146
147
148
# File 'lib/cult/node.rb', line 144

def addr(access, protocol = project.default_ip_protocol)
  fail ArgumentError unless [:public, :private].include?(access)
  fail ArgumentError unless [:ipv4, :ipv6].include?(protocol)
  send("#{protocol}_#{access}")
end

#addr_from(other, protocol = project.default_ip_protocol) ⇒ Object



156
157
158
# File 'lib/cult/node.rb', line 156

def addr_from(other, protocol = project.default_ip_protocol)
  same_network?(other) ? addr(:private, protocol) : addr(:public, protocol)
end

#cluster(*preds) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/cult/node.rb', line 161

def cluster(*preds)
  unless (preds - [:provider, :zone]).empty?
    fail ArgumentError, "invalid predicate: #{preds.inspect}"
  end

  preds.push(:provider) if preds.include?(:zone)

  col = project.nodes
  preds.each do |pred|
    col = col.select do |v|
      v.send(pred) == send(pred)
    end
  end
  col
end

#definition_parametersObject



84
85
86
# File 'lib/cult/node.rb', line 84

def definition_parameters
  super.merge(node: self)
end

#definition_pathObject



79
80
81
# File 'lib/cult/node.rb', line 79

def definition_path
  [ extra_path, state_path, node_path ]
end

#exist?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/cult/node.rb', line 69

def exist?
  File.exist?(state_path)
end

#extra_pathObject



89
90
91
# File 'lib/cult/node.rb', line 89

def extra_path
  File.join(path, 'extra.json')
end

#generate_ssh_keys!Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/cult/node.rb', line 125

def generate_ssh_keys!
  esc = ->(s) { Shellwords.escape(s) }
  tmp_public = ssh_private_key_file + '.pub'

  # Wanted to use -o and -t ecdsa, but Net::SSH still has some
  # issues with ECDSA, and only 4.0 beta supports -o style new keys
  cmd = "ssh-keygen -N '' -t rsa -b 4096 -C #{esc.(name)} " +
        "-f #{esc.(ssh_private_key_file)} && " +
        "mv #{esc.(tmp_public)} #{esc.(ssh_public_key_file)}"
  %x(#{cmd})

  unless $?.success?
    fail "Couldn't generate SSH key, command: #{cmd}"
  end

  File.chmod(0600, ssh_private_key_file)
end

#includesObject



94
95
96
# File 'lib/cult/node.rb', line 94

def includes
  definition.direct('roles') || super
end

#leader(role, *preds) ⇒ Object



188
189
190
191
192
193
# File 'lib/cult/node.rb', line 188

def leader(role, *preds)
  c = cluster(*preds)
  c = c.with(role: role) if role
  c = c.sort_by(&:created_at)
  c.first
end

#marshal_dumpObject



15
16
17
18
19
20
21
# File 'lib/cult/node.rb', line 15

def marshal_dump
  instance_variables.reject do |key|
    self.class.marshal_exclude.include?(key)
  end.map do |key|
    [key, instance_variable_get(key)]
  end.to_h
end

#marshal_load(vars) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/cult/node.rb', line 23

def marshal_load(vars)
  vars.each do |key, value|
    unless self.class.marshal_exclude.include?(key)
      instance_variable_set(key, value)
    end
  end
  self.project = Cult.project
end

#names_for_providerObject



228
229
230
# File 'lib/cult/node.rb', line 228

def names_for_provider
  [ provider_name ]
end

#names_for_zoneObject



232
233
234
# File 'lib/cult/node.rb', line 232

def names_for_zone
  [zone]
end

#node?Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/cult/node.rb', line 56

def node?
  true
end

#node_pathObject



65
66
67
# File 'lib/cult/node.rb', line 65

def node_path
  File.join(path, 'node.json')
end

#peers(*preds) ⇒ Object



178
179
180
# File 'lib/cult/node.rb', line 178

def peers(*preds)
  cluster(*preds).reject{|v| v == self}
end

#providerObject



99
100
101
# File 'lib/cult/node.rb', line 99

def provider
  project.providers[provider_name]
end

#provider_leader(role = nil) ⇒ Object



204
205
206
# File 'lib/cult/node.rb', line 204

def provider_leader(role = nil)
  leader(role, :provider)
end

#provider_leader?(role = nil) ⇒ Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/cult/node.rb', line 209

def provider_leader?(role = nil)
  provider_leader(role) == self
end

#provider_peersObject



183
184
185
# File 'lib/cult/node.rb', line 183

def provider_peers
  peers(:provider)
end

#role_leader(role) ⇒ Object



195
196
197
# File 'lib/cult/node.rb', line 195

def role_leader(role)
  leader(role)
end

#role_leader?(role) ⇒ Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/cult/node.rb', line 199

def role_leader?(role)
  role_leader(role) == self
end

#same_network?(other) ⇒ Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/cult/node.rb', line 151

def same_network?(other)
  [provider, zone] == [other.provider, other.zone]
end

#ssh_known_hosts_fileObject



115
116
117
# File 'lib/cult/node.rb', line 115

def ssh_known_hosts_file
  File.join(path, 'ssh.known-host')
end

#ssh_portObject



119
120
121
122
# File 'lib/cult/node.rb', line 119

def ssh_port
  # Moving SSH ports for security is lame.
  definition['ssh_port'] || 22
end

#ssh_private_key_fileObject



111
112
113
# File 'lib/cult/node.rb', line 111

def ssh_private_key_file
  File.join(path, 'ssh.key')
end

#ssh_public_key_fileObject



106
107
108
# File 'lib/cult/node.rb', line 106

def ssh_public_key_file
  File.join(path, 'ssh.pub')
end

#state_pathObject



74
75
76
# File 'lib/cult/node.rb', line 74

def state_path
  File.join(path, 'state.json')
end

#zone_leader(role = nil) ⇒ Object



214
215
216
# File 'lib/cult/node.rb', line 214

def zone_leader(role = nil)
  leader(role, :zone)
end

#zone_leader?(role = nil) ⇒ Boolean

Returns:

  • (Boolean)


219
220
221
# File 'lib/cult/node.rb', line 219

def zone_leader?(role = nil)
  zone_leader(role) == self
end

#zone_peersObject



224
225
226
# File 'lib/cult/node.rb', line 224

def zone_peers
  peers(:zone)
end