mirror of
https://github.com/czhu12/canine.git
synced 2026-01-06 11:40:44 -06:00
added predeploy command
This commit is contained in:
4
TODO.md
4
TODO.md
@@ -12,11 +12,7 @@
|
||||
- [ ] Show ingress logs at the cluster level -- parse NGINX logs
|
||||
- [ ] Streaming logs for pods
|
||||
- [ ] Project groupings?
|
||||
- [ ] Validate kubeconfig file
|
||||
- [ ] Create a pricing calculator
|
||||
<<<<<<< Updated upstream
|
||||
- [ ] Constantly refresh the processes page for readiness of pods
|
||||
=======
|
||||
- [ ] Pre-deploy task
|
||||
- [ ] Metrics improvement: https://stackoverflow.com/questions/68058199/chartjs-need-help-on-drawing-a-vertical-line-when-hovering-cursor
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
@@ -12,7 +12,8 @@ module Projects
|
||||
:docker_build_context_directory,
|
||||
:docker_command,
|
||||
:dockerfile_path,
|
||||
:container_registry_url
|
||||
:container_registry_url,
|
||||
:predeploy_command,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class Projects::DeploymentJob < ApplicationJob
|
||||
apply_config_map(project, kubectl)
|
||||
|
||||
deploy_volumes(project, kubectl)
|
||||
predeploy(project, deployment)
|
||||
predeploy(project, kubectl)
|
||||
# For each of the projects services
|
||||
deploy_services(project, kubectl)
|
||||
|
||||
@@ -53,15 +53,17 @@ class Projects::DeploymentJob < ApplicationJob
|
||||
end
|
||||
end
|
||||
|
||||
def predeploy(project, deployment)
|
||||
def predeploy(project, kubectl)
|
||||
return unless project.predeploy_command.present?
|
||||
|
||||
@logger.info("Running predeploy command: #{project.predeploy_command}", color: :yellow)
|
||||
success = system(project.predeploy_command)
|
||||
@logger.info("Running predeploy command: `#{project.predeploy_command}`...", color: :yellow)
|
||||
command = K8::Stateless::Command.new(project)
|
||||
command_yaml = command.to_yaml
|
||||
command.delete_if_exists!
|
||||
kubectl.apply_yaml(command_yaml)
|
||||
|
||||
return if success
|
||||
|
||||
raise DeploymentFailure, "Predeploy command failed for project #{project.name}"
|
||||
# Wait for the predeploy to finish
|
||||
command.wait_for_completion
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ module Cli
|
||||
|
||||
def call(command, envs: {})
|
||||
command = envs.map { |k, v| "#{k}=#{v}" }.join(" ") + " #{command}"
|
||||
@loggable.info(command.strip)
|
||||
Open3.popen3(command.strip) do |stdin, stdout, stderr, wait_thr|
|
||||
stdin.close
|
||||
stdout.each_line { |line| @loggable.info(line.chomp) }
|
||||
|
||||
61
app/services/k8/stateless/command.rb
Normal file
61
app/services/k8/stateless/command.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
class K8::Stateless::Command < K8::Base
|
||||
attr_accessor :project
|
||||
|
||||
def initialize(project)
|
||||
@project = project
|
||||
end
|
||||
|
||||
def kubectl
|
||||
@kubectl ||= K8::Kubectl.new(project.cluster.kubeconfig)
|
||||
end
|
||||
|
||||
def command
|
||||
project.predeploy_command
|
||||
end
|
||||
|
||||
def name
|
||||
"#{project.name}-predeployment"
|
||||
end
|
||||
|
||||
def namespace
|
||||
project.name
|
||||
end
|
||||
|
||||
def delete_if_exists!
|
||||
return if kubectl.call("get job #{name} -n #{namespace}").strip.empty?
|
||||
kubectl.call("delete job #{name} -n #{namespace}")
|
||||
rescue StandardError => e
|
||||
nil
|
||||
end
|
||||
|
||||
def wait_for_completion
|
||||
retries = 0
|
||||
while true
|
||||
break if done?
|
||||
sleep(3.0)
|
||||
retries += 1
|
||||
if retries > 30
|
||||
raise Projects::DeploymentJob::DeploymentFailure, "Predeploy command `#{command}` took too long to complete"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def done?
|
||||
_statuses = statuses
|
||||
if _statuses.include?("Failed") || _statuses.include?("ActiveDeadlineExceeded")
|
||||
raise Projects::DeploymentJob::DeploymentFailure, "Predeploy command `#{command}` failed"
|
||||
end
|
||||
_statuses.include?("Complete")
|
||||
end
|
||||
|
||||
def statuses
|
||||
begin
|
||||
output = kubectl.call("get job #{name} -n #{namespace} -o jsonpath='{.status.conditions[*].type}'")
|
||||
conditions = output.split
|
||||
conditions.map { |condition| condition.strip }
|
||||
rescue => e
|
||||
Rails.logger.error("Error checking job completion: #{e.message}")
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<%= turbo_frame_tag "new_service" do %>
|
||||
<div class="overflow-x-auto">
|
||||
<div>
|
||||
<%= form_with(model: [@project, @service], url: project_services_path) do |form| %>
|
||||
<div class="form-group">
|
||||
<%= form.label :name %>
|
||||
|
||||
43
resources/k8/stateless/command.yaml
Normal file
43
resources/k8/stateless/command.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: <%= name %>
|
||||
namespace: <%= project.name %>
|
||||
labels:
|
||||
caninemanaged: 'true'
|
||||
app: <%= project.name %>
|
||||
component: predeployment
|
||||
spec:
|
||||
backoffLimit: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: <%= project.name %>
|
||||
component: predeployment
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: <%= project.name %>
|
||||
image: <%= project.container_registry_url %>
|
||||
imagePullPolicy: Always
|
||||
command: <%= command.split.to_json %>
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: <%= project.name %>
|
||||
<% if @project.volumes.present? %>
|
||||
volumeMounts:
|
||||
<% @project.volumes.each do |volume| %>
|
||||
- name: <%= volume.name %>
|
||||
mountPath: <%= volume.mount_path %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
imagePullSecrets:
|
||||
- name: dockerconfigjson-github-com
|
||||
<% if @project.volumes.present? %>
|
||||
volumes:
|
||||
<% project.volumes.each do |volume| %>
|
||||
- name: <%= volume.name %>
|
||||
persistentVolumeClaim:
|
||||
claimName: <%= volume.name %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
Reference in New Issue
Block a user