Top Level Namespace

Defined Under Namespace

Classes: K8sDeploy

Constant Summary collapse

CONFIGURATION_OPTIONS =
{
  'git_branch' => 'GIT branch',
  'dockerfile' => 'Path to Dockerfile',
  'docker_platform' => 'Target platform, f.e linux/amd64 or linux/arm64',
  'container_registry' => 'Docker container registry',
  'gcloud_project_name' => 'GCloud project name',
  'kubernetes_context' => 'K8s context',
  'kubernetes_deployment_name' => 'K8s deployment name',
  'kubernetes_template_name' => 'K8s deployment -> template name',
  'kubernetes_docker_image_name' => 'K8s deployment -> template -> docker image'
}.freeze
DELIMITER_WIDTH =
80
CONSOLE_COLORS =
{
  red: "\x1b[31;01m",
  yellow: "\x1b[33;01m",
  green: "\x1b[32;01m",
  no_color: "\x1b[0m"
}.freeze

Instance Method Summary collapse

Instance Method Details

#block_output(header) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/k8s-deploy/tasks/console_formatters.rb', line 23

def block_output(header)
  prepared_header = color_output(:yellow) { " #{header} " }

  # adding 12 to fix size of non-visible color symbols
  puts
  puts prepared_header.center(DELIMITER_WIDTH + 12, '=')

  puts
  yield
  puts
end

#build_full_image_name(configuration) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/k8s-deploy/tasks/deploy.rb', line 16

def build_full_image_name(configuration)
  registry = configuration['container_registry']
  gcloud_project_name = configuration['gcloud_project_name']
  docker_image_name = configuration['kubernetes_docker_image_name']
  local_git_hash = get_git_hash(configuration)[0..6]
  tag = build_tag_name(local_git_hash)

  "#{registry}/#{gcloud_project_name}/#{docker_image_name}:#{tag}"
end

#build_tag_name(git_hash) ⇒ Object



7
8
9
# File 'lib/k8s-deploy/tasks/deploy.rb', line 7

def build_tag_name(git_hash)
  "#{build_timestamp}-#{git_hash}"
end

#build_timestampObject



3
4
5
# File 'lib/k8s-deploy/tasks/deploy.rb', line 3

def build_timestamp
  CURRENT_TIME.strftime('%Y%m%d%H%M%S')
end

#check_result_output(result) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/k8s-deploy/tasks/console_formatters.rb', line 35

def check_result_output(result)
  if result
    color_output(:green) { 'Ok' }
  else
    color_output(:red) { 'Fail' }
  end
end

#color_output(color) ⇒ Object

colorizing output



13
14
15
16
17
# File 'lib/k8s-deploy/tasks/console_formatters.rb', line 13

def color_output(color)
  raise 'Wrong color name' unless CONSOLE_COLORS.key?(color)

  CONSOLE_COLORS[color] + yield.to_s + CONSOLE_COLORS[:no_color]
end

#command_output(text) ⇒ Object



19
20
21
# File 'lib/k8s-deploy/tasks/console_formatters.rb', line 19

def command_output(text)
  puts "#> #{text}"
end

#get_git_hash(configuration) ⇒ Object



11
12
13
14
# File 'lib/k8s-deploy/tasks/deploy.rb', line 11

def get_git_hash(configuration)
  conf_branch = configuration['git_branch']
  `git rev-parse #{conf_branch}`
end


24
25
26
27
28
29
30
# File 'lib/k8s-deploy/tasks/configuration.rb', line 24

def print_configuration(configuration)
  max_name_length = CONFIGURATION_OPTIONS.values.map(&:length).max
  CONFIGURATION_OPTIONS.each do |key, name|
    value = configuration.fetch(key, '')
    puts "#{name.rjust(max_name_length)}: #{color_output(:green) { value }}"
  end
end


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/k8s-deploy/tasks/deploy.rb', line 26

def print_deploy_build(configuration)
  conf_branch = configuration['git_branch']
  new_image_name = build_full_image_name(configuration)

  puts "New name:\t#{color_output(:green) { new_image_name }}"
  puts
  new_git_hash = get_git_hash(configuration)[0..6]
  puts "New GIT hash:\t#{color_output(:green) { new_git_hash }}"

  git_hash = `git rev-parse #{conf_branch}`
  git_info = `git log -1 --format=full #{git_hash}`

  puts
  puts "\t\t--- GIT commit info ---"
  git_info.each_line do |line|
    puts "\t\t#{line}"
  end
  puts "\t\t-----------------------"
  puts
  puts "New Timestamp:\t#{color_output(:green) { build_timestamp }}"
  puts

  dockerfile_path = configuration['dockerfile']
  docker_platform = configuration['docker_platform']
  command = "docker buildx build --platform #{docker_platform} -t #{new_image_name} -f #{dockerfile_path} ."
  command_output(command)
  puts

  system command
end


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/k8s-deploy/tasks/deploy.rb', line 68

def print_deploy_deployment_patch(configuration)
  deployment_name = configuration['kubernetes_deployment_name']
  template_name = configuration['kubernetes_template_name']
  new_image_name = build_full_image_name(configuration)

  json_template = {
    spec: {
      template: {
        spec: {
          containers: [{
            name: template_name,
            image: new_image_name
          }]
        }
      }
    }
  }

  template_string = JSON.dump(json_template)

  command = "kubectl patch deployment #{deployment_name} -p " \
            "'#{template_string}' --record"

  command_output(command)
  puts

  print color_output(:yellow) { 'Confirm deploy (y/N): ' }

  puts
  case $stdin.gets.strip
  when 'Y', 'y', 'Yes', 'yes'
    puts color_output(:green) { 'Starting deploy...' }
    system command
    puts
    puts 'Now you can check deploy status with ' \
         "#{color_output(:yellow) { 'status' }} command."
  else
    puts color_output(:red) { 'Deploy terminated.' }
    exit 1
  end
end


57
58
59
60
61
62
63
64
65
66
# File 'lib/k8s-deploy/tasks/deploy.rb', line 57

def print_deploy_push(configuration)
  new_image_name = build_full_image_name(configuration)
  command = "docker push #{new_image_name}"
  command_output(command)
  puts
  system command
  puts
  puts 'Sleeping for 5 seconds...'
  sleep 5
end


110
111
112
113
114
115
116
117
# File 'lib/k8s-deploy/tasks/deploy.rb', line 110

def print_deploy_rollback(configuration)
  deployment_name = configuration['kubernetes_deployment_name']
  command = "kubectl rollout undo deployment #{deployment_name}"

  command_output(command)
  puts
  system command
end


119
120
121
122
123
124
125
126
127
# File 'lib/k8s-deploy/tasks/deploy.rb', line 119

def print_deploy_scale(configuration, replicas_count)
  deployment_name = configuration['kubernetes_deployment_name']
  command = "kubectl scale deployment #{deployment_name} " \
            "--replicas=#{replicas_count}"

  command_output(command)
  puts
  system command
end


3
4
5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/k8s-deploy/tasks/status.rb', line 3

def print_deployment_status(configuration)
  deployment_name = configuration['kubernetes_deployment_name']

  basic_info_command = "kubectl get deployment #{deployment_name} --show-labels"
  command_output(basic_info_command)
  puts
  system basic_info_command
  puts

  describe_command = "kubectl describe deployment #{deployment_name}"
  command_output(describe_command)
  puts
  system describe_command
end


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/k8s-deploy/tasks/status.rb', line 27

def print_docker_image_status(configuration)
  deployment_name = configuration['kubernetes_deployment_name']

  command = "kubectl get deployment #{deployment_name} -o template " \
            "'--template={{(index .spec.template.spec.containers 0).image}}'"

  command_output(command)
  puts

  docker_image = `#{command}`
  puts "Full name:\t#{color_output(:green) { docker_image }}"

  time_hash = docker_image.split(':').last
  git_hash = time_hash.split('-').last
  timestamp = time_hash.split('-').first

  puts

  # check git_hash is valid
  if git_hash && /^[a-f0-9]+$/.match(git_hash)
    puts "GIT hash:\t#{color_output(:green) { git_hash }}"
    git_info = `git log -1 --format=full #{git_hash}`

    puts
    puts "\t\t--- GIT commit info ---"
    git_info.each_line do |line|
      puts "\t\t#{line}"
    end
    puts "\t\t-----------------------"
  else
    puts color_output(:red) { "ERROR! Can't parse GIT hash from tag!" }
  end

  puts
  begin
    time_utc = Time.strptime("#{timestamp} UTC", '%Y%m%d%H%M%S %Z')
    puts "Timestamp:\t#{color_output(:green) { timestamp }}"
    puts "Time (UTC):\t#{time_utc}"
    puts "Time (local):\t#{time_utc.getlocal}"
  rescue ArgumentError
    puts color_output(:red) { "ERROR! Can't parse timestamp from tag!" }
  end
end


41
42
43
44
45
46
47
48
49
# File 'lib/k8s-deploy/tasks/check.rb', line 41

def print_gcloud_check_kubectl_context(configuration)
  conf_k8s_context = configuration['kubernetes_context']
  current_k8s_context = `kubectl config view -o jsonpath='{.current-context}'`
  check_result = current_k8s_context == conf_k8s_context

  puts 'Your K8s context should be ' \
       "#{color_output(:green) { conf_k8s_context }}:\t" \
       "#{check_result_output(check_result)}"
end


31
32
33
34
35
36
37
38
39
# File 'lib/k8s-deploy/tasks/check.rb', line 31

def print_gcloud_check_project(configuration)
  conf_gcloud_project = configuration['gcloud_project_name']
  current_gcloud_project = `gcloud beta config get-value project`
  check_result = current_gcloud_project.include?(conf_gcloud_project)

  puts 'Your GCloud project should be ' \
       "#{color_output(:green) { conf_gcloud_project }}:\t" \
       "#{check_result_output(check_result)}"
end


3
4
5
6
7
8
9
10
11
# File 'lib/k8s-deploy/tasks/check.rb', line 3

def print_git_check_branch(configuration)
  conf_branch = configuration['git_branch']
  local_branch = `git rev-parse --abbrev-ref HEAD`.strip
  check_result = local_branch == conf_branch

  puts 'Your local branch must be ' \
       "#{color_output(:green) { conf_branch }}:\t\t" \
       "#{check_result_output(check_result)}"
end


20
21
22
23
24
25
26
27
28
29
# File 'lib/k8s-deploy/tasks/check.rb', line 20

def print_git_check_remote_branch(configuration)
  conf_branch = configuration['git_branch']

  local_git_hash = `git rev-parse #{conf_branch}`
  remote_git_hash = `git rev-parse origin/#{conf_branch}`
  check_result = local_git_hash == remote_git_hash

  puts "Your local version must be same as GitHub:\t" \
       "#{check_result_output(check_result)}"
end


13
14
15
16
17
18
# File 'lib/k8s-deploy/tasks/check.rb', line 13

def print_git_check_uncommitted
  check_result = `git status --porcelain`.empty?

  puts "Your local branch must be clear:\t\t" \
       "#{check_result_output(check_result)}"
end


18
19
20
21
22
23
24
25
# File 'lib/k8s-deploy/tasks/status.rb', line 18

def print_pods_status(configuration)
  template_name = configuration['kubernetes_template_name']

  command = "kubectl get pods --show-labels -l name=#{template_name}"
  command_output(command)
  puts
  system command
end

#validate_configuration(configuration) ⇒ Object



15
16
17
18
19
20
21
22
# File 'lib/k8s-deploy/tasks/configuration.rb', line 15

def validate_configuration(configuration)
  missed_parameters = CONFIGURATION_OPTIONS.keys - configuration.keys

  return if missed_parameters.empty?

  params_string = missed_parameters.join(', ')
  raise "Missed parameters in configuration: #{params_string}."
end