Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[430] added clusters api #431

Merged
merged 18 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,5 @@ deployment:
subdomain:
length_limit: 63
default_job_retry_count: 5
vcluster:
max_creation_retry_count: 5
47 changes: 34 additions & 13 deletions core/app/clients/uffizzi_core/controller_client.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class UffizziCore::ControllerClient
class ConnectionError < StandardError; end

attr_accessor :connection

def initialize
Expand All @@ -11,18 +13,6 @@ def apply_config_file(deployment_id:, config_file_id:, body:)
connection.post("/deployments/#{deployment_id}/config_files/#{config_file_id}", body)
end

def deployment(deployment_id:)
get("/deployments/#{deployment_id}")
end

def create_deployment(deployment_id:, body:)
connection.post("/deployments/#{deployment_id}", body)
end

def delete_deployment(deployment_id:)
connection.delete("/deployments/#{deployment_id}")
end

def deployment_containers(deployment_id:)
get("/deployments/#{deployment_id}/containers")
end
Expand Down Expand Up @@ -68,14 +58,44 @@ def get_deployments_usage_metrics_containers(deployment_ids:, begin_at:, end_at:
get('/deployments/usage_metrics/containers', query_params)
end

def create_namespace(body:)
post('/namespaces', body)
end

def namespace(namespace:)
get("/namespaces/#{namespace}")
end

def delete_namespace(namespace:)
connection.delete("/namespaces/#{namespace}")
end

def create_cluster(namespace:, body:)
post("/namespaces/#{namespace}/cluster", body)
end

def show_cluster(namespace:)
get("/namespaces/#{namespace}/cluster")
end

private

def get(url, params = {})
response = connection.get(url, params)
make_request(:get, url, params)
end

def post(url, params = {})
make_request(:post, url, params)
end

def make_request(method, url, params)
response = connection.send(method, url, params)
body = response.body
underscored_body = UffizziCore::Converters.deep_underscore_keys(body)

RequestResult.quiet.new(code: response.status, result: underscored_body)
rescue Faraday::ServerError
raise ConnectionError
end

def build_connection
Expand All @@ -96,6 +116,7 @@ def build_connection
interval: connection.next_retry_timeout_seconds,
exceptions: handled_exceptions)
conn.response(:json)
conn.response(:raise_error)
conn.adapter(Faraday.default_adapter)
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module UffizziCore::Api::Cli::V1::Projects::ClustersControllerModule
private

def update_show_trial_quota_exceeded_warning; end

def stop_if_deployment_forbidden; end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

class UffizziCore::Api::Cli::V1::Projects::ClustersController < UffizziCore::Api::Cli::V1::Projects::ApplicationController
include UffizziCore::Api::Cli::V1::Projects::ClustersControllerModule

before_action :authorize_uffizzi_core_api_cli_v1_projects_clusters
before_action :stop_if_deployment_forbidden, only: [:create]
after_action :update_show_trial_quota_exceeded_warning, only: [:create, :destroy]

def index
clusters = resource_project.clusters.enabled

respond_with clusters
end

def create
cluster_form = UffizziCore::Api::Cli::V1::Cluster::CreateForm.new(cluster_params)
cluster_form.project = resource_project
cluster_form.deployed_by = current_user
return respond_with cluster_form unless cluster_form.save

UffizziCore::ClusterService.start_deploy(cluster_form)

respond_with cluster_form
end

def show
respond_with resource_cluster
end

def destroy
resource_cluster.disable!

head(:no_content)
end

private

def resource_cluster
@resource_cluster ||= resource_project.clusters.enabled.find_by!(name: params[:name])
end

def cluster_params
params.require(:cluster)
end
end
19 changes: 19 additions & 0 deletions core/app/forms/uffizzi_core/api/cli/v1/cluster/create_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class UffizziCore::Api::Cli::V1::Cluster::CreateForm < UffizziCore::Cluster
include UffizziCore::ApplicationForm

permit :name, :manifest

validate :check_manifest, if: -> { manifest.present? }

private

def check_manifest
YAML.load_stream(manifest)
rescue Psych::SyntaxError => e
err = [e.problem, e.context].compact.join(' ')

errors.add(:manifest, err)
end
end
12 changes: 12 additions & 0 deletions core/app/jobs/uffizzi_core/cluster/delete_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

class UffizziCore::Cluster::DeleteJob < UffizziCore::ApplicationJob
sidekiq_options queue: :deployments, retry: 5

def perform(id)
Rails.logger.info("DEPLOYMENT_PROCESS cluster_id=#{id} DeleteJob")

cluster = UffizziCore::Cluster.find(id)
UffizziCore::ControllerService.delete_namespace(cluster)
end
end
11 changes: 11 additions & 0 deletions core/app/jobs/uffizzi_core/cluster/deploy_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class UffizziCore::Cluster::DeployJob < UffizziCore::ApplicationJob
sidekiq_options queue: :deployments, retry: 5

def perform(id)
cluster = UffizziCore::Cluster.find(id)

UffizziCore::ClusterService.deploy_cluster(cluster)
end
end
11 changes: 11 additions & 0 deletions core/app/jobs/uffizzi_core/cluster/manage_deploying_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class UffizziCore::Cluster::ManageDeployingJob < UffizziCore::ApplicationJob
sidekiq_options queue: :deployments, retry: 5

def perform(id, try = 1)
cluster = UffizziCore::Cluster.find(id)

UffizziCore::ClusterService.manage_deploying(cluster, try)
end
end
2 changes: 1 addition & 1 deletion core/app/jobs/uffizzi_core/config_file/apply_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def perform(deployment_id, config_file_id)
return
end

unless UffizziCore::ControllerService.deployment_exists?(deployment)
unless UffizziCore::ControllerService.namespace_exists?(deployment)
raise UffizziCore::DeploymentNotFoundError,
deployment_id
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def perform(deployment_id, credential_id)
return
end

unless UffizziCore::ControllerService.deployment_exists?(deployment)
unless UffizziCore::ControllerService.namespace_exists?(deployment)
raise UffizziCore::DeploymentNotFoundError,
deployment_id
end
Expand Down
2 changes: 1 addition & 1 deletion core/app/jobs/uffizzi_core/deployment/create_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def perform(id)

deployment = UffizziCore::Deployment.find(id)

UffizziCore::ControllerService.create_deployment(deployment)
UffizziCore::ControllerService.create_namespace(deployment)

UffizziCore::Deployment::CreateCredentialsJob.perform_async(deployment.id)
end
Expand Down
3 changes: 2 additions & 1 deletion core/app/jobs/uffizzi_core/deployment/delete_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class UffizziCore::Deployment::DeleteJob < UffizziCore::ApplicationJob
def perform(id)
Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{id} DeleteJob")

UffizziCore::ControllerService.delete_deployment(id)
deployment = UffizziCore::Deployment.find(id)
UffizziCore::ControllerService.delete_namespace(deployment)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def perform(id, repeated = false)
return
end

raise UffizziCore::DeploymentNotFoundError, id unless UffizziCore::ControllerService.deployment_exists?(deployment)
raise UffizziCore::DeploymentNotFoundError, id unless UffizziCore::ControllerService.namespace_exists?(deployment)

UffizziCore::DeploymentService.deploy_containers(deployment, repeated)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def perform(deployment_id, credential_id)
return
end

unless UffizziCore::ControllerService.deployment_exists?(deployment)
unless UffizziCore::ControllerService.namespace_exists?(deployment)
raise UffizziCore::DeploymentNotFoundError,
deployment_id
end
Expand Down
1 change: 1 addition & 0 deletions core/app/lib/uffizzi_core/concerns/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module UffizziCore::Concerns::Models::Account
has_many :projects, dependent: :destroy
has_many :deployments, through: :projects
has_many :payments, dependent: :destroy
has_many :clusters, through: :projects

aasm(:sso_state) do
state :connection_not_configured, initial: true
Expand Down
56 changes: 56 additions & 0 deletions core/app/lib/uffizzi_core/concerns/models/cluster.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

module UffizziCore::Concerns::Models::Cluster
extend ActiveSupport::Concern
include UffizziCore::ClusterRepo

included do
include AASM

self.table_name = UffizziCore.table_names[:clusters]

belongs_to :project, class_name: UffizziCore::Project.name
belongs_to :deployed_by, class_name: UffizziCore::User.name, foreign_key: :deployed_by_id, optional: true
validates_uniqueness_of :name, conditions: -> { enabled }
validates :name, presence: true, format: { with: /([A-Za-z0-9\-_]+)/ }

aasm(:state) do
state :deploying_namespace, initial: true
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user creates an empty cluster, will it be stuck in the deploying_namespace state?

state :failed_deploy_namespace
state :deploying
state :deployed
state :failed
state :disabled

event :start_deploying do
transitions from: [:deploying_namespace], to: :deploying
end

event :fail_deploy_namespace do
transitions from: [:deploying_namespace], to: :failed_deploy_namespace
end

event :finish_deploy do
transitions from: [:deploying], to: :deployed
end

event :fail do
transitions from: [:deploying], to: :failed
end

event :disable, after: :after_disable do
transitions from: [:fail_deploy_namespace, :deploying, :deployed, :failed], to: :disabled
end
end

def after_disable
UffizziCore::Cluster::DeleteJob.perform_async(id)
end

def namespace
return name if name.present?

"cluster-#{id}"
end
end
end
4 changes: 4 additions & 0 deletions core/app/lib/uffizzi_core/concerns/models/deployment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ def clean
def preview_url
"#{subdomain}.#{Settings.app.managed_dns_zone}"
end

def namespace
"deployment-#{id}"
end
end
# rubocop:enable Metrics/BlockLength
end
1 change: 1 addition & 0 deletions core/app/lib/uffizzi_core/concerns/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module UffizziCore::Concerns::Models::Project
has_many :compose_files, dependent: :destroy
has_many :secrets, dependent: :destroy, as: :resource
has_many :host_volume_files, dependent: :destroy
has_many :clusters, dependent: :destroy

validates :name, presence: true, uniqueness: { scope: :account, message: 'Name already exists' }
validates :slug, presence: true, uniqueness: { message: 'Project slug already taken' }
Expand Down
1 change: 1 addition & 0 deletions core/app/lib/uffizzi_core/concerns/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module UffizziCore::Concerns::Models::User
has_many :user_projects, dependent: :destroy
has_many :projects, through: :user_projects
has_many :deployments, class_name: UffizziCore::Deployment.name, foreign_key: :deployed_by_id, dependent: :nullify
has_many :clusters, foreign_key: :deployed_by_id

has_one_attached :avatar

Expand Down
5 changes: 5 additions & 0 deletions core/app/models/uffizzi_core/cluster.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class UffizziCore::Cluster < ApplicationRecord
include UffizziCore::Concerns::Models::Cluster
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class UffizziCore::Api::Cli::V1::Projects::ClustersPolicy < UffizziCore::ApplicationPolicy
def index?
context.user_access_module.any_access_to_project?(context.user, context.project)
end

def show?
context.user_access_module.any_access_to_project?(context.user, context.project)
end

def create?
context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
end

def destroy?
context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
end
end
1 change: 1 addition & 0 deletions core/app/repositories/uffizzi_core/account_repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ module UffizziCore::AccountRepo
included do
scope :by_kind, ->(kind) { where(kind: kind) }
scope :personal, -> { by_kind(UffizziCore::Account.kind.personal) }
scope :organizational, -> { by_kind(UffizziCore::Account.kind.organizational) }
end
end
10 changes: 10 additions & 0 deletions core/app/repositories/uffizzi_core/cluster_repo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module UffizziCore::ClusterRepo
extend ActiveSupport::Concern

included do
scope :deployed, -> { where(state: UffizziCore::Cluster::STATE_DEPLOYED) }
scope :enabled, -> { where.not(state: UffizziCore::Cluster::STATE_DISABLED) }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class UffizziCore::Api::Cli::V1::Projects::ClusterSerializer < UffizziCore::BaseSerializer
type :cluster

attributes :name, :state, :kubeconfig
end
Loading