class Siren::Song

Attributes

env[R]
services[R]

Public Class Methods

load(filename) click to toggle source
# File lib/siren/song.rb, line 9
def self.load (filename)
  new(YAML.load(File.read(filename)))
end
new(data) click to toggle source
# File lib/siren/song.rb, line 13
def initialize (data)
  @name = data["metadata"]["name"]
  @ns = data["metadata"]["namespace"] || @name
  @spec = data["spec"]
  process()
end

Public Instance Methods

annotations() click to toggle source
# File lib/siren/song.rb, line 60
def annotations
  {
    "siren.altaire.xyz/song": @name,
  }
end
env_to_k8s(hash) click to toggle source
# File lib/siren/song.rb, line 52
def env_to_k8s (hash)
  res = []
  hash.each do |name, value|
    res << { name: name, value: value }
  end
  res
end
get(what, key) click to toggle source
# File lib/siren/song.rb, line 20
def get (what, key)
  return [] unless what.has_key?(key)
  val = what[key]
  if val.is_a?(Array)
    if val.count{|v|v.is_a?(Hash) && !(v.has_key?(:name) || v.has_key?("name") || v.has_key?(:fullName) || v.has_key?("fullName"))} > 1
      raise "`#{key}`: only one can be anonymous"
    end
    return val
  end
  return [val]
end
makename(base, obj, name = "name", fullName = "fullName", suffix = nil) click to toggle source
# File lib/siren/song.rb, line 66
def makename (base, obj, name = "name", fullName = "fullName", suffix = nil)

  return obj[fullName] if obj[fullName]
  [base, name ? obj[name] : nil, suffix].compact.join("-")
end
process() click to toggle source
# File lib/siren/song.rb, line 32
def process ()
  @env = {}
  @env.merge! process_env(@spec["env"] || {})
  @services = get(@spec, "service").map do |svc|
    svc
  end
end
process_env(hash) click to toggle source
# File lib/siren/song.rb, line 40
def process_env (hash)
  hash = hash.dup
  hash.map do |name, value|
    next unless value.is_a?(Hash)
    case value.keys[0]
    when "encrypt"
      hash[name] = { "secure" => Siren::Crypto.encrypt(value.values[0]) }
    end
  end
  return hash
end
to_certificate(svc) click to toggle source
# File lib/siren/song.rb, line 135
def to_certificate (svc)
  name = makename(@name, svc)
  get(svc, "publish").map do |publish|
    get(publish, "domain").map do |domain|
      @stack.things << {
        apiVersion: "cert-manager.io/v1alpha2",
        kind: "Certificate",
        metadata: {
          annotations: annotations,
          name: name,
          namespace: @ns,
        }.compact,
        spec: {
          secretName: [name, get(publish, "domain").length > 1 ? domain : nil, "tls"].compact.join("-"),
          duration: "2160h",
          renewBefore: "360h",
          commonName: domain,
          dnsNames: [domain],
          issuerRef: {kind: "ClusterIssuer", name: "letsencrypt-production"},
        },
      }
    end
  end
end
to_deployment(svc) click to toggle source
# File lib/siren/song.rb, line 72
def to_deployment (svc)
  name = makename(@name, svc)
  @stack.things << {
    apiVersion: "apps/v1",
    kind: "Deployment",
    metadata: {
      annotations: annotations,
      name: name,
      namespace: @ns,
    }.compact,
    spec: {
      selector: {
        matchLabels: {
          service: name
        }
      },
      template: {
        metadata: {
          annotations: annotations,
          labels: {
            service: name
          }
        },
        spec: {
          containers: [
            image: svc["image"],
            env: env_to_k8s(env.merge(svc["env"] || {})),
          ],
          imagePullSecrets: [{ name: "regcred" }],
        }
      },
    },
  }
end
to_domain(svc) click to toggle source
# File lib/siren/song.rb, line 160
def to_domain (svc)
  name = makename(@name, svc)
  get(svc, "publish").map do |publish|
    get(publish, "domain").map do |domain|
      @stack.things << {
        apiVersion: "altaire.com/v1alpha1",
        kind: "Domain",
        metadata: {
          annotations: annotations,
          name: [name, get(publish, "domain").length > 1 ? domain : nil].compact.join("-"),
          namespace: @ns,
        }.compact,
        spec: {
          domain: domain,
          service: publish["loadBalancer"] ? makename(name, publish["loadBalancer"]) : "traefik",
        }
      }
    end
  end
end
to_ingress_route(svc) click to toggle source
# File lib/siren/song.rb, line 181
def to_ingress_route (svc)
  name = makename(@name, svc)
  get(svc, "publish").map do |publish|
    next if publish["loadBalancer"]
    get(publish, "domain").map do |domain|
      @stack.things << {
        apiVersion: "traefik.containo.us/v1alpha1",
        kind: "IngressRoute",
        metadata: {
          annotations: annotations,
          name: [name, get(publish, "domain").length > 1 ? domain : nil].compact.join("-"),
          namespace: @ns,
        }.compact,
        spec: {
          tls: { secretName: [name, get(publish, "domain").length > 1 ? domain : nil, "tls"].compact.join("-") },
          routes: [
            {
              match: "Host(`#{domain}`)",
              kind: "Rule",
              services: [
                {
                  name: name,
                  port: 80,
                }
              ],
              middlewares: publish["auth"] ? [{name: "altaire-auth"}] : []
            }
          ]
        }
      }
    end
  end
end
to_namespace() click to toggle source
# File lib/siren/song.rb, line 215
def to_namespace ()
  return if @ns == nil
  @stack.things << {
    apiVersion: "v1",
    kind: "Namespace",
    metadata: {
      annotations: annotations,
      name: @ns,
    }.compact,
  }
end
to_service(svc) click to toggle source
# File lib/siren/song.rb, line 107
def to_service (svc)
  svcname = makename(@name, svc)
  get(svc, "publish").group_by{|x|x["loadBalancer"]}.each do |loadbalancer, publish|
    name = makename(svcname, publish[0], "loadBalancer")
    @stack.things << {
      apiVersion: "v1",
      kind: "Service",
      metadata: {
        annotations: annotations,
        name: name,
        namespace: @ns,
      }.compact,
      spec: {
        selector: {
          service: svcname,
        },
        ports: publish.map do |publish|
          {
            targetPort: publish["port"] || 80,
            port: publish["externalPort"] || publish["port"] || 80,
          }
        end,
        type: loadbalancer ? "LoadBalancer" : nil
      }.compact,
    }
  end
end
to_stack() click to toggle source
# File lib/siren/song.rb, line 227
def to_stack ()
  @stack = Stack.new
  to_namespace()
  @services.each do |svc|
    to_deployment(svc)
    to_service(svc)
    to_certificate(svc)
    to_domain(svc)
    to_ingress_route(svc)
  end
  @stack
end