class Hippo::Stage

Attributes

config_root[R]
wd[R]

Public Class Methods

new(wd, config_root, options) click to toggle source
# File lib/hippo/stage.rb, line 14
def initialize(wd, config_root, options)
  @wd = wd
  @config_root = config_root
  @options = options
end

Public Instance Methods

all_objects() click to toggle source

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

@return [Hash]

# 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) click to toggle source

Apply a series of objecst with

@param objects [Array<Hippo::ObjectDefinition>] @return [Hash]

# 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
branch() click to toggle source
# File lib/hippo/stage.rb, line 28
def branch
  @options['branch']
end
command(name) click to toggle source
# 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
config() click to toggle source
# File lib/hippo/stage.rb, line 44
def config
  @options['config']
end
configs() click to toggle source

Return an array of all configuration objects

@return [Hash<String,Hippo::ObjectDefinition>]

# File lib/hippo/stage.rb, line 155
def configs
  @configs ||= Util.create_object_definitions(objects('config'), self)
end
context() click to toggle source
# File lib/hippo/stage.rb, line 40
def context
  @options['context']
end
decorator() click to toggle source

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

# 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) click to toggle source

Delete an object from the kubernetes API

@param names [Array<String>] @return [Boolean]

# 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_objects() click to toggle source

Remove any objects which are prunable

@return [void]

# 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
deployments() click to toggle source

Return an array of all deployments for this stage

@return [Hash<String,Hippo::ObjectDefinition>]

# File lib/hippo/stage.rb, line 141
def deployments
  @deployments ||= Util.create_object_definitions(objects('deployments'), self, required_kinds: ['Deployment'])
end
get(*names) click to toggle source

Get some data from the kubernetes API

@param names [Array<String>] @return [Array<Hippo::ObjectDefinition>]

# 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_tag() click to toggle source
# File lib/hippo/stage.rb, line 32
def image_tag
  @options['image-tag']
end
images() click to toggle source
# 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) click to toggle source

Return an array of all job objects

@return [Hash<String,Hippo::ObjectDefinition>]

# File lib/hippo/stage.rb, line 162
def jobs(type)
  @jobs ||= {}
  @jobs[type] ||= Util.create_object_definitions(objects("jobs/#{type}"), self)
end
kubectl(*commands) click to toggle source

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

@return [Array<String>]

# 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) click to toggle source

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

@return [Array<Hash>]

# 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
manifest() click to toggle source
# File lib/hippo/stage.rb, line 20
def manifest
  wd.manifest
end
name() click to toggle source
# File lib/hippo/stage.rb, line 24
def name
  @options['name']
end
namespace() click to toggle source
# File lib/hippo/stage.rb, line 36
def namespace
  @options['namespace']
end
objects(path) click to toggle source
# File lib/hippo/stage.rb, line 130
def objects(path)
  manifest.objects(path, decorator: decorator)
end
overridden_package_values() click to toggle source

Return any package values that have been defined

@return [Hash]

# File lib/hippo/stage.rb, line 193
def overridden_package_values
  @options['packages'] || {}
end
packages() click to toggle source

Return a hash of all packages available in the stage

@return [Hash<String, Hippo::Package>]

# 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
readme() click to toggle source
# File lib/hippo/stage.rb, line 94
def readme
  return unless manifest.readme

  decorator.call(manifest.readme)
end
secret_manager() click to toggle source
# File lib/hippo/stage.rb, line 134
def secret_manager
  @secret_manager ||= SecretManager.new(self)
end
services() click to toggle source

Return an array of all services/ingresses for this stage

@return [Hash<String,Hippo::ObjectDefinition>]

# 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_vars() click to toggle source

These are the vars to represent this

# 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) click to toggle source

Wait for the named jobs to complete

# 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