Skip to content

Commit

Permalink
Merge pull request #431 from UffizziCloud/feature/430_uffizzi_cluster…
Browse files Browse the repository at this point in the history
…_api

[430] added clusters api
  • Loading branch information
moklidia authored Jul 3, 2023
2 parents 64d23ff + b86757b commit 542c5c3
Show file tree
Hide file tree
Showing 46 changed files with 661 additions and 78 deletions.
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
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: [:failed_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

0 comments on commit 542c5c3

Please sign in to comment.