Class: Hippo::Stage

Inherits:
Object
  • Object
show all
Defined in:
lib/hippo/stage.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(wd, config_root, options) ⇒ Stage

Returns a new instance of Stage.



14
15
16
17
18
# File 'lib/hippo/stage.rb', line 14

def initialize(wd, config_root, options)
  @wd = wd
  @config_root = config_root
  @options = options
end

Instance Attribute Details

#config_rootObject (readonly)

Returns the value of attribute config_root.



12
13
14
# File 'lib/hippo/stage.rb', line 12

def config_root
  @config_root
end

#wdObject (readonly)

Returns the value of attribute wd.



11
12
13
# File 'lib/hippo/stage.rb', line 11

def wd
  @wd
end

Instance Method Details

#all_objectsHash

Return an array of all objects that should be managed by Hippo

Returns:



170
171
172
173
174
175
176
177
178
# File 'lib/hippo/stage.rb', line 170

def all_objects
  @all_objects ||= begin
    all = (deployments | services | configs | jobs('install') | jobs('deploy'))
    all.each_with_object({}) do |object, hash|
      hash[object.kind] ||= {}
      hash[object.kind][object.name] = object
    end
  end
end

#apply(objects) ⇒ Hash

Apply a series of objecst with

Parameters:

Returns:

Raises:



212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/hippo/stage.rb', line 212

def apply(objects)
  command = ['kubectl']
  command += ['--context', context] if context
  command += ['apply', '-f', '-']

  yaml_to_apply = objects.map(&:yaml_to_apply).join("\n")

  stdout, stderr, status = Open3.capture3(command.join(' '), stdin_data: yaml_to_apply + "\n")

  raise Error, "[kubectl] #{stderr}" unless status.success?

  Util.parse_kubectl_apply_lines(stdout)
end

#branchObject



28
29
30
# File 'lib/hippo/stage.rb', line 28

def branch
  @options['branch']
end

#command(name) ⇒ Object



48
49
50
51
52
53
54
55
56
# File 'lib/hippo/stage.rb', line 48

def command(name)
  base = manifest.commands[name]
  return nil if base.nil?

  {
    target: base['target'],
    command: decorator.call(base['command'])
  }
end

#configObject



44
45
46
# File 'lib/hippo/stage.rb', line 44

def config
  @options['config']
end

#configsHash<String,Hippo::ObjectDefinition>

Return an array of all configuration objects

Returns:



155
156
157
# File 'lib/hippo/stage.rb', line 155

def configs
  @configs ||= Util.create_object_definitions(objects('config'), self)
end

#contextObject



40
41
42
# File 'lib/hippo/stage.rb', line 40

def context
  @options['context']
end

#decoratorObject

Return a new decorator object that can be passed to objects that would like to decorator things.



83
84
85
86
87
88
89
90
91
92
# File 'lib/hippo/stage.rb', line 83

def decorator
  proc do |data|
    begin
      template = Liquid::Template.parse(data)
      template.render(template_vars, filters: [LiquidFilters])
    rescue Liquid::SyntaxError => e
      raise Error, "Template error: #{e.message}"
    end
  end
end

#delete(*names) ⇒ Boolean

Delete an object from the kubernetes API

Parameters:

  • names (Array<String>)

Returns:

  • (Boolean)


244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/hippo/stage.rb', line 244

def delete(*names)
  command = kubectl('delete', *names)
  stdout, stderr, status = Open3.capture3(*command)
  if status.success?
    Util.parse_kubectl_apply_lines(stdout)
    true
  else
    if stderr =~ /\" not found$/
      false
    else
      raise Error, "[kutectl] #{stderr}"
    end
  end
end

#delete_pruneable_objectsvoid

This method returns an undefined value.

Remove any objects which are prunable



123
124
125
126
127
128
# File 'lib/hippo/stage.rb', line 123

def delete_pruneable_objects
  live_objects(pruneable_only: true).each do |object|
    object = object[:live]
    delete(object.kind, object.name)
  end
end

#deploymentsHash<String,Hippo::ObjectDefinition>

Return an array of all deployments for this stage

Returns:



141
142
143
# File 'lib/hippo/stage.rb', line 141

def deployments
  @deployments ||= Util.create_object_definitions(objects('deployments'), self, required_kinds: ['Deployment'])
end

#get(*names) ⇒ Array<Hippo::ObjectDefinition>

Get some data from the kubernetes API

Parameters:

  • names (Array<String>)

Returns:

Raises:



230
231
232
233
234
235
236
237
238
# File 'lib/hippo/stage.rb', line 230

def get(*names)
  command = kubectl('get', '-o', 'yaml', *names)
  stdout, stderr, status = Open3.capture3(*command)
  raise Error, "[kubectl] #{stderr}" unless status.success?

  yaml = YAML.safe_load(stdout, permitted_classes: [Time])
  yaml = yaml['items'] || [yaml]
  yaml.map { |y| ObjectDefinition.new(y, self, clean: true) }
end

#image_tagObject



32
33
34
# File 'lib/hippo/stage.rb', line 32

def image_tag
  @options['image-tag']
end

#imagesObject



58
59
60
61
62
# File 'lib/hippo/stage.rb', line 58

def images
  @images ||= manifest.images.deep_merge(@options['images'] || {}).each_with_object({}) do |(key, image), hash|
    hash[key] = Image.new(key, image)
  end
end

#jobs(type) ⇒ Hash<String,Hippo::ObjectDefinition>

Return an array of all job objects

Returns:



162
163
164
165
# File 'lib/hippo/stage.rb', line 162

def jobs(type)
  @jobs ||= {}
  @jobs[type] ||= Util.create_object_definitions(objects("jobs/#{type}"), self)
end

#kubectl(*commands) ⇒ Array<String>

Return a kubectl command ready for use within this stage’s namespace and context

Returns:

  • (Array<String>)


201
202
203
204
205
206
# File 'lib/hippo/stage.rb', line 201

def kubectl(*commands)
  prefix = ['kubectl']
  prefix += ['--context', context] if context
  prefix += ['-n', namespace]
  prefix + commands
end

#live_objects(pruneable_only: false) ⇒ Array<Hash>

Return an array of objects that currently exist on the kubernetesa API.

Returns:



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/hippo/stage.rb', line 104

def live_objects(pruneable_only: false)
  los = get(all_objects.keys.join(','), '--selector', 'app.kubernetes.io/managed-by=hippo')
  los.each_with_object([]) do |live_obj, array|
    local = all_objects.dig(live_obj.kind, live_obj.name)
    pruneable = local.nil? && (live_obj.kind != 'Secret' && live_obj.name != 'hippo-secret-key')

    next if pruneable_only && !pruneable

    array << {
      live: live_obj,
      local: local,
      pruneable: pruneable
    }
  end
end

#manifestObject



20
21
22
# File 'lib/hippo/stage.rb', line 20

def manifest
  wd.manifest
end

#nameObject



24
25
26
# File 'lib/hippo/stage.rb', line 24

def name
  @options['name']
end

#namespaceObject



36
37
38
# File 'lib/hippo/stage.rb', line 36

def namespace
  @options['namespace']
end

#objects(path) ⇒ Object



130
131
132
# File 'lib/hippo/stage.rb', line 130

def objects(path)
  manifest.objects(path, decorator: decorator)
end

#overridden_package_valuesHash

Return any package values that have been defined

Returns:



193
194
195
# File 'lib/hippo/stage.rb', line 193

def overridden_package_values
  @options['packages'] || {}
end

#packagesHash<String, Hippo::Package>

Return a hash of all packages available in the stage

Returns:



183
184
185
186
187
188
# File 'lib/hippo/stage.rb', line 183

def packages
  @packages ||= objects('packages').values.each_with_object({}) do |package_hash, hash|
    package = Package.new(package_hash.first, self)
    hash[package.name] = package
  end
end

#readmeObject



94
95
96
97
98
# File 'lib/hippo/stage.rb', line 94

def readme
  return unless manifest.readme

  decorator.call(manifest.readme)
end

#secret_managerObject



134
135
136
# File 'lib/hippo/stage.rb', line 134

def secret_manager
  @secret_manager ||= SecretManager.new(self)
end

#servicesHash<String,Hippo::ObjectDefinition>

Return an array of all services/ingresses for this stage

Returns:



148
149
150
# File 'lib/hippo/stage.rb', line 148

def services
  @services ||= Util.create_object_definitions(objects('services'), self, required_kinds: %w[Service Ingress NetworkPolicy])
end

#template_varsObject

These are the vars to represent this



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/hippo/stage.rb', line 65

def template_vars
  @template_vars ||= begin
    {
      'manifest' => manifest.template_vars,
      'stage-name' => name,
      'branch' => branch,
      'image-tag' => image_tag,
      'namespace' => namespace,
      'context' => context,
      'images' => images.values.each_with_object({}) { |image, hash| hash[image.name] = image.template_vars },
      'config' => manifest.config.deep_merge(config),
      'secrets' => secret_manager.all
    }
  end
end

#wait_for_jobs(names, times = 120) ⇒ Object

Wait for the named jobs to complete



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/hippo/stage.rb', line 260

def wait_for_jobs(names, times = 120)
  jobs = nil
  times.times do
    jobs = get(*names)

    if jobs.all? { |j| j['status']['active'].nil? }
      return [false, jobs]
    else
      sleep 2
    end
  end

  [true, jobs]
end