class DeployConfig

Public Instance Methods

main() click to toggle source
# File lib/deploy_config.rb, line 9
def main
  options = get_options

  take_approval_deploy_params(options)

  take_approval_app_env(options)

  deploy_config(options)
end

Private Instance Methods

app_container_env_vars_cmd(spec) click to toggle source
# File lib/deploy_config.rb, line 223
def app_container_env_vars_cmd(spec)
  env_export_cmd = ''
  spec[:env].each do |env|
    env_var_val = ENV.fetch(env[:name]) { env[:value] }
    env_export_cmd += "export #{env[:name]}=#{env_var_val} && "
  end

  env_export_cmd
end
app_container_spec(app_name, namespace) click to toggle source
# File lib/deploy_config.rb, line 217
def app_container_spec(app_name, namespace)
  deploy_containers = `kubectl get deployment -n #{namespace} #{app_name} --output=jsonpath={.spec.template.spec.containers}`
  return nil if deploy_containers == ''
  JSON.parse(deploy_containers, symbolize_names: true).find { |container| container[:name] == app_name }
end
build_image(image_url, gcr_url, options) click to toggle source
# File lib/deploy_config.rb, line 127
def build_image(image_url, gcr_url, options)
  commit_image_tag = ENV['CI_COMMIT_SHORT_SHA'] || `git rev-parse --short HEAD`
  time_image_tag=`TZ=IST-5:30 date +'%Y.%m.%d.%HH.%MM.%SS'`
  commit_image_url = "#{gcr_url}:#{commit_image_tag}".strip
  time_image_url = "#{gcr_url}:#{time_image_tag}".strip

  project_id = options[:project_id]

  shell_cmd("gcloud builds submit --project #{project_id} --timeout=20m --tag #{time_image_url} || true")

  shell_cmd("gcloud container images add-tag --quiet #{time_image_url} #{commit_image_url}")

  shell_cmd("gcloud container images add-tag --quiet #{time_image_url} #{image_url}")

  image_url
end
deploy_config(options) click to toggle source
# File lib/deploy_config.rb, line 144
def deploy_config(options)
  shell_cmd(
    "gcloud container clusters get-credentials #{options[:cluster]} " \
    "--region #{options[:cluster_location]} " \
    "--project #{options[:project_id]} "
  )

  spec = app_container_spec(options[:app_name], options[:namespace]) || {}

  override_envs = override_envs(options)
  k8s_deployment_envs = k8s_deployment_envs(options)

  yaml_file = `kustomize build deploy/overlays/#{options[:kuztomize_env]}`

  yaml_file.scan(/\$[A-Z_]+/).each do |env_name|
    env_key = env_name[1..-1]
    env_val = override_envs[env_key] || ENV[env_key] || k8s_deployment_envs[env_key]
    next if env_val.nil?
    yaml_file.gsub!(/\$#{env_key}\s*$/, "'#{env_val}'")
  end

  gcr_url = "gcr.io/#{options[:project_id]}/#{options[:image_repo] || options[:app_name]}"
  opt_image_url = options[:image_tag] && "#{gcr_url}:#{options[:image_tag]}"

  image_url = "#{gcr_url}:current"
  image_url = spec[:image] if validate_image_tag_exists?(spec[:image])
  image_url = opt_image_url if validate_image_tag_exists?(opt_image_url)

  if !validate_image_tag_exists?(image_url)
    build_image(image_url, gcr_url, options)
  end

  yaml_file.gsub!(/\$IMAGE_URL/, image_url)

  FileUtils.mkdir_p('./tmp')

  File.write('./tmp/final.yaml', yaml_file)

  puts "\e[36m\e[1m#{yaml_file}\e[22m\e[0m"

  shell_cmd("kubectl apply -f ./tmp/final.yaml")

  shell_cmd("kubectl rollout status deployment/#{options[:app_name]} -n #{options[:namespace]}")
end
get_options() click to toggle source
# File lib/deploy_config.rb, line 21
def get_options
  options = {}

  require_options_keys = [:project_id, :app_name, :namespace, :cluster, :cluster_location, :kuztomize_env]

  opt_parser = OptionParser.new do |opts|
    opts.banner = "Usage: ather deploy config [options]"

    opts.on("-y", "Auto approve") do |flag|
      options[:approve] = flag
    end

    opts.on("--image-tag IMAGE_TAG", "Image tag to deploy [optional]") do |val|
      options[:image_tag] = val
    end

    opts.on("--image-repo IMAGE_REPO", "Image repo to deploy [optional] default to K8s app name") do |val|
      options[:image_repo] = val
    end

    opts.on("--project-id PROJECT_ID", "GCP project id [required or set env var PROJECT_ID]") do |val|
      options[:project_id] = val
    end

    opts.on("--app-name APP_NAME", "K8s app name [required or set env var APP_NAME]") do |val|
      options[:app_name] = val
    end

    opts.on("--namespace NAMESPACE", "K8s app namespace [required or set env var NAMESPACE]") do |val|
      options[:namespace] = val
    end

    opts.on("--cluster CLUSTER", "App name [required or set env var CLUSTER]") do |val|
      options[:cluster] = val
    end

    opts.on("--cluster-location CLUSTER_LOCATION", "App name [required or set env var CLUSTER_LOCATION]") do |val|
      options[:cluster_location] = val
    end

    opts.on("--kuztomize-env KUZTOMIZE_ENV", "App name [required or set env var KUZTOMIZE_ENV]") do |val|
      options[:kuztomize_env] = val
    end

    opts.on("-h", "--help", "Prints this help") do
      puts opts
      exit
    end
  end

  opt_parser.parse!

  require_options_keys.each do |key|
    options[key] ||= ENV[key.to_s.upcase]
    if options[key].nil?
      puts "ERROR: Required option --#{key.to_s.gsub('_', '-')} or set env var #{key.to_s.upcase} \n"
      opt_parser.parse! %w[--help]
      exit 1
    end
  end

  options
end
k8s_deployment_envs(options) click to toggle source
# File lib/deploy_config.rb, line 203
def k8s_deployment_envs(options)
  spec = app_container_spec(options[:app_name], options[:namespace])

  return {} if spec.nil?

  k8s_deployment_envs = {}

  spec[:env].each do |env|
    k8s_deployment_envs[env[:name]] = env[:value]
  end

  k8s_deployment_envs
end
override_envs(options) click to toggle source
# File lib/deploy_config.rb, line 189
def override_envs(options)
  override_env_filepath = "./deploy/env/#{options[:kuztomize_env]}.yaml"
  override_envs = {}

  if File.file?(override_env_filepath)
    env = YAML.load_file(override_env_filepath, symbolize_names: true)
    env[:env].each do |env|
      override_envs[env[:name]] = env[:value]
    end
  end

  override_envs
end
shell_cmd(cmd) click to toggle source
# File lib/deploy_config.rb, line 85
def shell_cmd(cmd)
  puts "EXECUTING : \e[32m\e[1m#{cmd}\e[22m\e[0m"
  op = system(cmd)
  if !op
    puts "FAILED : \e[31m\e[1m#{cmd}\e[22m\e[0m"
    exit 1
  end
  puts "SUCCESS : \e[32m\e[1m#{cmd}\e[22m\e[0m"
end
take_approval_app_env(options) click to toggle source
# File lib/deploy_config.rb, line 108
def take_approval_app_env(options)
  override_env_filepath = "./deploy/env/#{options[:kuztomize_env]}.sh"
  return if !File.file?(override_env_filepath)
  puts "\e[32m\e[1mOverriding Application enviroment variables \e[22m\e[0m"

  app_envs = `cat #{override_env_filepath}`.gsub('export ', "\n")
  puts "\e[34m\e[1m#{app_envs}\e[22m\e[0m"

  return if(options[:approve])
  puts 'Are you sure to want to deploy the above application enviroment variables? (y/N)'
  confirmation = STDIN.gets.strip
  return if(confirmation == 'y' || confirmation == 'Y')
  exit
end
take_approval_deploy_params(options) click to toggle source
# File lib/deploy_config.rb, line 95
def take_approval_deploy_params(options)
  puts "\e[32m\e[1mDeployment parameter details \e[22m\e[0m"
  options.each do |key, val|
    puts "\e[1m#{key} = \e[31m#{val}\e[0m \e[22m"
  end

  return if(options[:approve])
  puts 'Are you sure to want to deploy as per the above deployment parameters? (y/N)'
  confirmation = STDIN.gets.strip
  return if(confirmation == 'y' || confirmation == 'Y')
  exit
end
validate_image_tag_exists?(image_url) click to toggle source
# File lib/deploy_config.rb, line 123
def validate_image_tag_exists?(image_url)
  system("gcloud container images describe #{image_url}")
end