module Cluster class Runner def launch return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists start_cluster run_command "kubectl delete pod -n kube-system #{pods("kube-system").map { |pod| pod[:name] if pod[:name].start_with? "registry-creds" } .compact.join(" ")}" run_command "kubectl rollout status -n kube-system deployment/registry-creds" post_start end def start_cluster if SctCore::Helper.operatingSystem == SctCore::Helper::MAC_OS run_command "#{minikube} start --cpus=$(sysctl -n hw.ncpu) --memory=8G" else run_command "#{minikube} start --cpus=$(cat /proc/cpuinfo | grep processor | wc -l) --memory=10G" end run_command "#{minikube} ssh -- 'sudo su -c \"echo 10048576 > /proc/sys/fs/inotify/max_user_watches\"'" update_config end def post_start wait_for_pods run_command "sudo sct hostfile" UI.success("\nāœ”ļø You can visit your environment at šŸ‘‰ https://spend-cloud.spend.cloud.local šŸ‘Œ") end def down run_command "#{minikube} stop" end def reset run_command "#{minikube} delete" start_cluster create_secrets run_command "#{minikube} addons enable registry-creds" run_command "#{minikube} addons enable ingress" run_command "kubectl rollout status -n kube-system deployment/registry-creds" run_command "kubectl rollout status -n kube-system deployment/nginx-ingress-controller" wait_for_gcr_secret run_command "kubectl apply -f ~/development/spend-cloud/k8s/ingress.yml" wait_for_ingress_ip run_command "kubectl apply -f ~/development/spend-cloud/k8s/dependencies.yml" wait_for_pods run_command "kubectl apply -f ~/development/spend-cloud/k8s/" post_start end def wait_for_pods UI.important("Waiting for pods to become ready...") while ! pods.all? { |pod| pod[:status] == "Running" } delete_stalled_pods sleep 5 end UI.success("Pods are now ready.") end def delete_stalled_pods(feedback: false) return UI.success("No stalled pods found") unless !pods.to_a.empty? stalled_pods = pods.select { |pod| pod[:stalled] } if stalled_pods.empty? UI.success("There are no stalled pods.") if feedback else run_command "kubectl delete pods #{stalled_pods.map { |pod| pod[:name] } .join(" ")}" end end def update_config if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS windows_home_path = SctCore::Helper.windowsHomePath kube_file_path = windows_home_path+"/.kube/config" if !File.exists?(kube_file_path) return UI.error("#{kube_file_path} doesn't exist") end run_command "sed -e 's~\\\\~/~g' -e 's~C:~/mnt/c~g' < #{kube_file_path} > ~/.kube/minikube-config" UI.success("#{kube_file_path} copied to ~/.kube/minikube-config") end run_command "kubectl config use-context minikube" run_command "kubectl replace -n kube-system -f #{File.expand_path('../../resources/corefile.yml', __dir__)}" old_list = pods("kube-system").map { |pod| pod[:name] if pod[:name].start_with? "coredns" }.compact run_command "kubectl delete pod -n kube-system #{old_list.join(" ")}" unless old_list.to_a.empty? run_command "kubectl rollout status -n kube-system deployment/coredns" end def pods(namespace = nil) if namespace output = `kubectl get pods -n #{namespace}` else output = `kubectl get pods` end # split output lines lines = output.split "\n" # exclude first line (table header) lines = lines[1..-1] if lines.to_a.empty? return end # get name and status of each pod lines.map do |line| columns = line.split(" ") name = columns[0] status = columns[2] stalled = status == "ErrImagePull" || status == "ImagePullBackOff" { name: name, status: status, stalled: stalled } end end def create_secrets run_command "kubectl create secret generic gcloud-credentials --from-file=\"$(echo ~)/.config/gcloud/application_default_credentials.json\"" run_command "kubectl create secret generic -n kube-system registry-creds-dpr --from-literal DOCKER_PRIVATE_REGISTRY_PASSWORD=changeme --from-literal DOCKER_PRIVATE_REGISTRY_SERVER=changeme --from-literal DOCKER_PRIVATE_REGISTRY_USER=changeme" run_command "kubectl patch secret -n kube-system registry-creds-dpr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"dpr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'" run_command "kubectl create secret generic -n kube-system registry-creds-ecr --from-literal AWS_ACCESS_KEY_ID=changeme --from-literal AWS_SECRET_ACCESS_KEY=changeme --from-literal AWS_SESSION_TOKEN=\"\" --from-literal aws-account=changeme --from-literal aws-assume-role=changeme --from-literal aws-region=changeme" run_command "kubectl patch secret -n kube-system registry-creds-ecr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"ecr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'" run_command "kubectl create secret generic -n kube-system registry-creds-gcr --from-file=\"$(echo ~)/.config/gcloud/application_default_credentials.json\" --from-literal=gcrurl=\"https://eu.gcr.io\"" run_command "kubectl patch secret -n kube-system registry-creds-gcr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"gcr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'" run_command "kubectl create secret generic -n kube-system registry-creds-acr --from-literal ACR_PASSWORD=changeme --from-literal ACR_CLIENT_ID=changeme --from-literal ACR_URL=changeme" run_command "kubectl patch secret -n kube-system registry-creds-acr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"acr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'" end def wait_for_gcr_secret UI.important("Waiting for Google Cloud Registry secret to become available...") while ! `kubectl get secrets`.include? "gcr-secret" sleep 5 end UI.success("Google Cloud Registry secret is now available.") end def wait_for_ingress_ip UI.important("Waiting for ingress IP to become available...") while `kubectl describe ingress | grep "Address" | awk '{print $2}'`.empty? sleep 5 end UI.success("Ingress IP is now available.") end def status print_contexts print_minikube_status if get_minikube_status.find_all { |status| status[1] == 'Stopped' }.count == 0 print_pods_status("kube-system") print_pods_status else UI.important("Please check your minikube status. If all services are stopped you should start the minikube first.") end end def print_contexts output = `kubectl config get-contexts` lines = output.split "\n" lines = lines[1..-1] rows = lines.map do |line| columns = line.split(" ") current_context = columns[0] == "*" ? "Yes".green : "No".red [columns[2], current_context] end puts Terminal::Table.new title: "Contexts".green, headings: ['Cluster', 'Using context'], rows: rows end def print_minikube_status puts Terminal::Table.new title: "Minikube status".green, headings: ['Name', 'Status'], rows: get_minikube_status end def get_minikube_status output = `#{minikube} status` lines = output.split "\n" rows = lines.map do |line| columns = line.split(" ") [columns[0][0..-2], columns[1]] end end def print_pods_status(namespace = nil) pods_list = pods(namespace) if pods_list.to_a.empty? return end rows = pods_list.map do |pod| [ pod[:name], pod[:status] == "Running" ? pod[:status].green : pod[:status].red ] end puts Terminal::Table.new title: "Pods (namespace: #{namespace || "default"})".green, headings: ['Name', 'Status'], rows: rows end def run_command command if ! system command raise command.red end end def minikube if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS return "minikube.exe" else return "minikube" end end end end