uffizzi_core 2.1.29 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/app/clients/uffizzi_core/controller_client.rb +40 -23
  3. data/app/controller_modules/uffizzi_core/api/cli/v1/projects/clusters_controller_module.rb +9 -0
  4. data/app/controllers/concerns/uffizzi_core/auth_management.rb +17 -1
  5. data/app/controllers/uffizzi_core/api/cli/v1/accounts/projects_controller.rb +7 -1
  6. data/app/controllers/uffizzi_core/api/cli/v1/accounts_controller.rb +45 -0
  7. data/app/controllers/uffizzi_core/api/cli/v1/projects/clusters_controller.rb +46 -0
  8. data/app/forms/uffizzi_core/api/cli/v1/cluster/create_form.rb +19 -0
  9. data/app/jobs/uffizzi_core/cluster/delete_job.rb +12 -0
  10. data/app/jobs/uffizzi_core/cluster/deploy_job.rb +11 -0
  11. data/app/jobs/uffizzi_core/cluster/manage_deploying_job.rb +11 -0
  12. data/app/jobs/uffizzi_core/config_file/apply_job.rb +1 -1
  13. data/app/jobs/uffizzi_core/deployment/create_credential_job.rb +1 -1
  14. data/app/jobs/uffizzi_core/deployment/create_job.rb +1 -1
  15. data/app/jobs/uffizzi_core/deployment/delete_job.rb +2 -1
  16. data/app/jobs/uffizzi_core/deployment/deploy_containers_job.rb +1 -1
  17. data/app/jobs/uffizzi_core/deployment/update_credential_job.rb +1 -1
  18. data/app/lib/uffizzi_core/concerns/models/account.rb +1 -0
  19. data/app/lib/uffizzi_core/concerns/models/cluster.rb +54 -0
  20. data/app/lib/uffizzi_core/concerns/models/deployment.rb +4 -0
  21. data/app/lib/uffizzi_core/concerns/models/project.rb +1 -0
  22. data/app/lib/uffizzi_core/concerns/models/user.rb +1 -0
  23. data/app/models/uffizzi_core/cluster.rb +5 -0
  24. data/app/policies/uffizzi_core/api/cli/v1/accounts/projects_policy.rb +4 -0
  25. data/app/policies/uffizzi_core/api/cli/v1/accounts_policy.rb +11 -0
  26. data/app/policies/uffizzi_core/api/cli/v1/projects/clusters_policy.rb +19 -0
  27. data/app/repositories/uffizzi_core/account_repo.rb +1 -0
  28. data/app/repositories/uffizzi_core/cluster_repo.rb +10 -0
  29. data/app/serializers/uffizzi_core/api/cli/v1/account_serializer.rb +9 -0
  30. data/app/serializers/uffizzi_core/api/cli/v1/projects/cluster_serializer.rb +7 -0
  31. data/app/serializers/uffizzi_core/controller/create_cluster/cluster_serializer.rb +9 -0
  32. data/app/services/uffizzi_core/cluster_service.rb +44 -0
  33. data/app/services/uffizzi_core/controller_service.rb +43 -21
  34. data/app/services/uffizzi_core/logs_service.rb +1 -1
  35. data/config/routes.rb +5 -2
  36. data/db/migrate/20230613101901_create_clusters.rb +19 -0
  37. data/lib/uffizzi_core/version.rb +1 -1
  38. data/lib/uffizzi_core.rb +1 -0
  39. metadata +19 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c97fb24aa0b59fec57a431af483f81a030afa9260fc7f0db21488edc0ad88842
4
- data.tar.gz: e96d6f8d5b97de2d35e5311ab4cacb081a09713f1c75452d3a895c3caf73c190
3
+ metadata.gz: a3857b5cc3f90f134b4ce7275290e460c4abf7868dcdc8d3940390efbab73fc9
4
+ data.tar.gz: 99d1c61e2af05d005a2c30314bf726ed2f68442c8cafaf1c036fc5294294d286
5
5
  SHA512:
6
- metadata.gz: 94efb8590f5b3575978921342816d7fe48355af568f2c6e693093b64b1ac8fae5533f859e5567b201d3d67254f107fc703167ad59b1b6016376b88ab3bab5398
7
- data.tar.gz: f258d75612c7abfda4ca2aea0bafecba4274d91cf3ecbe663051f5ef6a0614177d3666931a9317d7d6fcf7c11a2c8c22fb2ce38a1ffee4760e1d29e67f93cf5b
6
+ metadata.gz: 9437c1c50d81bd7e6de3419ae81ef1d4035204b1e153249ae2a233918faf36e9267f6b58b200a73a77b335f5d03f4c2f7b1aebf39d7ed08e765b31941663da3d
7
+ data.tar.gz: 574c4e039f9f5a6ad4204b696ba6778eeb5ed88d729a5cda724b9d3a20e790f01547cf4b16c3a88bdd105da388bcd2c99e6e00194a8210d5c407845055bc1d93
@@ -1,28 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::ControllerClient
4
+ class ConnectionError < StandardError; end
5
+
4
6
  attr_accessor :connection
5
7
 
6
- def initialize
7
- @connection = build_connection
8
+ def initialize(connection_settings)
9
+ @connection = build_connection(connection_settings)
8
10
  end
9
11
 
10
12
  def apply_config_file(deployment_id:, config_file_id:, body:)
11
13
  connection.post("/deployments/#{deployment_id}/config_files/#{config_file_id}", body)
12
14
  end
13
15
 
14
- def deployment(deployment_id:)
15
- get("/deployments/#{deployment_id}")
16
- end
17
-
18
- def create_deployment(deployment_id:, body:)
19
- connection.post("/deployments/#{deployment_id}", body)
20
- end
21
-
22
- def delete_deployment(deployment_id:)
23
- connection.delete("/deployments/#{deployment_id}")
24
- end
25
-
26
16
  def deployment_containers(deployment_id:)
27
17
  get("/deployments/#{deployment_id}/containers")
28
18
  end
@@ -68,34 +58,61 @@ class UffizziCore::ControllerClient
68
58
  get('/deployments/usage_metrics/containers', query_params)
69
59
  end
70
60
 
61
+ def create_namespace(body:)
62
+ post('/namespaces', body)
63
+ end
64
+
65
+ def namespace(namespace:)
66
+ get("/namespaces/#{namespace}")
67
+ end
68
+
69
+ def delete_namespace(namespace:)
70
+ connection.delete("/namespaces/#{namespace}")
71
+ end
72
+
73
+ def create_cluster(namespace:, body:)
74
+ post("/namespaces/#{namespace}/cluster", body)
75
+ end
76
+
77
+ def show_cluster(namespace:, name:)
78
+ get("/namespaces/#{namespace}/cluster/#{name}")
79
+ end
80
+
71
81
  private
72
82
 
73
83
  def get(url, params = {})
74
- response = connection.get(url, params)
84
+ make_request(:get, url, params)
85
+ end
86
+
87
+ def post(url, params = {})
88
+ make_request(:post, url, params)
89
+ end
90
+
91
+ def make_request(method, url, params)
92
+ response = connection.send(method, url, params)
75
93
  body = response.body
76
94
  underscored_body = UffizziCore::Converters.deep_underscore_keys(body)
77
95
 
78
96
  RequestResult.quiet.new(code: response.status, result: underscored_body)
97
+ rescue Faraday::ServerError
98
+ raise ConnectionError
79
99
  end
80
100
 
81
- def build_connection
82
- controller = Settings.controller
83
- login = controller.login
84
- password = controller.password
85
- url = controller.url
86
- connection = controller.connection
101
+ def build_connection(settings)
102
+ connection = settings.connection
87
103
  handled_exceptions = Faraday::Request::Retry::DEFAULT_EXCEPTIONS + [Faraday::ConnectionFailed]
88
104
 
89
- Faraday.new(url) do |conn|
105
+ Faraday.new(settings.url) do |conn|
90
106
  conn.options.timeout = connection.timeout
91
107
  conn.options.open_timeout = connection.open_timeout
92
- conn.request(:basic_auth, login, password)
108
+ conn.request(:basic_auth, settings.login, settings.password)
93
109
  conn.request(:json)
94
110
  conn.request(:retry,
95
111
  max: connection.retires_count,
96
112
  interval: connection.next_retry_timeout_seconds,
97
113
  exceptions: handled_exceptions)
98
114
  conn.response(:json)
115
+ conn.response(:raise_error)
99
116
  conn.adapter(Faraday.default_adapter)
100
117
  end
101
118
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::Api::Cli::V1::Projects::ClustersControllerModule
4
+ private
5
+
6
+ def update_show_trial_quota_exceeded_warning; end
7
+
8
+ def stop_if_deployment_forbidden; end
9
+ end
@@ -14,7 +14,23 @@ module UffizziCore::AuthManagement
14
14
  end
15
15
 
16
16
  def current_user
17
- @current_user ||= UffizziCore::User.find_by(id: session[:user_id])
17
+ @current_user ||= UffizziCore::User.find_by(id: current_user_id)
18
+ end
19
+
20
+ def auth_token
21
+ header = request.headers['Authorization']
22
+ header&.split(' ')&.last
23
+ end
24
+
25
+ def current_user_id
26
+ return session[:user_id] if session[:user_id].present?
27
+ return unless auth_token.present?
28
+
29
+ decoded_token = UffizziCore::TokenService.decode(auth_token)
30
+ return unless decoded_token
31
+ return if decoded_token.first['expires_at'] < DateTime.now
32
+
33
+ decoded_token.first['user_id']
18
34
  end
19
35
 
20
36
  def authenticate_request!
@@ -5,6 +5,12 @@
5
5
  class UffizziCore::Api::Cli::V1::Accounts::ProjectsController < UffizziCore::Api::Cli::V1::Accounts::ApplicationController
6
6
  before_action :authorize_uffizzi_core_api_cli_v1_accounts_projects
7
7
 
8
+ def index
9
+ projects = resource_account.projects.active
10
+
11
+ respond_with projects, each_serializer: UffizziCore::Api::Cli::V1::ShortProjectSerializer
12
+ end
13
+
8
14
  # Create a project
9
15
  #
10
16
  # @path [POST] /api/cli/v1/accounts/{account_id}/projects
@@ -17,7 +23,7 @@ class UffizziCore::Api::Cli::V1::Accounts::ProjectsController < UffizziCore::Api
17
23
 
18
24
  def create
19
25
  project_form = UffizziCore::Api::Cli::V1::Project::CreateForm.new(project_params)
20
- project_form.account = current_user.accounts.find(params[:account_id])
26
+ project_form.account = resource_account
21
27
  UffizziCore::ProjectService.add_users_to_project!(project_form, project_form.account) if project_form.save
22
28
 
23
29
  respond_with project_form
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @resource Project
4
+
5
+ class UffizziCore::Api::Cli::V1::AccountsController < UffizziCore::Api::Cli::V1::ApplicationController
6
+ before_action :authorize_uffizzi_core_api_cli_v1_accounts
7
+
8
+ # Get accounts of current user
9
+ #
10
+ # @path [GET] /api/cli/v1/accounts
11
+ #
12
+ # @response [object<accounts: Array<object<id: integer, name: string>> >] 200 OK
13
+ # @response 401 Not authorized
14
+ def index
15
+ accounts = current_user.accounts.order(name: :desc)
16
+
17
+ respond_with accounts
18
+ end
19
+
20
+ # Get account by name
21
+ #
22
+ # @path [GET] /api/cli/v1/accounts/{name}
23
+ #
24
+ # @response [object<account: <object<id: integer, name: string, projects: Array<object<id: integer, slug: string>>>> >] 200 OK
25
+ # @response 401 Not authorized
26
+ def show
27
+ respond_with resource_account
28
+ end
29
+
30
+ private
31
+
32
+ def policy_context
33
+ account = resource_account || current_user.default_account
34
+
35
+ UffizziCore::AccountContext.new(current_user, user_access_module, account, params)
36
+ end
37
+
38
+ def resource_account
39
+ @resource_account ||= if params[:name]
40
+ current_user.accounts.find_by!(name: params[:name])
41
+ else
42
+ current_user.default_account
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::ClustersController < UffizziCore::Api::Cli::V1::Projects::ApplicationController
4
+ include UffizziCore::Api::Cli::V1::Projects::ClustersControllerModule
5
+
6
+ before_action :authorize_uffizzi_core_api_cli_v1_projects_clusters
7
+ before_action :stop_if_deployment_forbidden, only: [:create]
8
+ after_action :update_show_trial_quota_exceeded_warning, only: [:create, :destroy]
9
+
10
+ def index
11
+ clusters = resource_project.clusters.enabled
12
+
13
+ respond_with clusters
14
+ end
15
+
16
+ def create
17
+ cluster_form = UffizziCore::Api::Cli::V1::Cluster::CreateForm.new(cluster_params)
18
+ cluster_form.project = resource_project
19
+ cluster_form.deployed_by = current_user
20
+ return respond_with cluster_form unless cluster_form.save
21
+
22
+ UffizziCore::ClusterService.start_deploy(cluster_form)
23
+
24
+ respond_with cluster_form
25
+ end
26
+
27
+ def show
28
+ respond_with resource_cluster
29
+ end
30
+
31
+ def destroy
32
+ resource_cluster.disable!
33
+
34
+ head(:no_content)
35
+ end
36
+
37
+ private
38
+
39
+ def resource_cluster
40
+ @resource_cluster ||= resource_project.clusters.enabled.find_by!(name: params[:name])
41
+ end
42
+
43
+ def cluster_params
44
+ params.require(:cluster)
45
+ end
46
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Cluster::CreateForm < UffizziCore::Cluster
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :name, :manifest
7
+
8
+ validate :check_manifest, if: -> { manifest.present? }
9
+
10
+ private
11
+
12
+ def check_manifest
13
+ YAML.load_stream(manifest)
14
+ rescue Psych::SyntaxError => e
15
+ err = [e.problem, e.context].compact.join(' ')
16
+
17
+ errors.add(:manifest, err)
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cluster::DeleteJob < UffizziCore::ApplicationJob
4
+ sidekiq_options queue: :deployments, retry: 5
5
+
6
+ def perform(id)
7
+ Rails.logger.info("DEPLOYMENT_PROCESS cluster_id=#{id} DeleteJob")
8
+
9
+ cluster = UffizziCore::Cluster.find(id)
10
+ UffizziCore::ControllerService.delete_namespace(cluster)
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cluster::DeployJob < UffizziCore::ApplicationJob
4
+ sidekiq_options queue: :deployments, retry: 5
5
+
6
+ def perform(id)
7
+ cluster = UffizziCore::Cluster.find(id)
8
+
9
+ UffizziCore::ClusterService.deploy_cluster(cluster)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cluster::ManageDeployingJob < UffizziCore::ApplicationJob
4
+ sidekiq_options queue: :deployments, retry: 5
5
+
6
+ def perform(id, try = 1)
7
+ cluster = UffizziCore::Cluster.find(id)
8
+
9
+ UffizziCore::ClusterService.manage_deploying(cluster, try)
10
+ end
11
+ end
@@ -28,7 +28,7 @@ class UffizziCore::ConfigFile::ApplyJob < UffizziCore::ApplicationJob
28
28
  return
29
29
  end
30
30
 
31
- unless UffizziCore::ControllerService.deployment_exists?(deployment)
31
+ unless UffizziCore::ControllerService.namespace_exists?(deployment)
32
32
  raise UffizziCore::DeploymentNotFoundError,
33
33
  deployment_id
34
34
  end
@@ -29,7 +29,7 @@ class UffizziCore::Deployment::CreateCredentialJob < UffizziCore::ApplicationJob
29
29
  return
30
30
  end
31
31
 
32
- unless UffizziCore::ControllerService.deployment_exists?(deployment)
32
+ unless UffizziCore::ControllerService.namespace_exists?(deployment)
33
33
  raise UffizziCore::DeploymentNotFoundError,
34
34
  deployment_id
35
35
  end
@@ -8,7 +8,7 @@ class UffizziCore::Deployment::CreateJob < UffizziCore::ApplicationJob
8
8
 
9
9
  deployment = UffizziCore::Deployment.find(id)
10
10
 
11
- UffizziCore::ControllerService.create_deployment(deployment)
11
+ UffizziCore::ControllerService.create_namespace(deployment)
12
12
 
13
13
  UffizziCore::Deployment::CreateCredentialsJob.perform_async(deployment.id)
14
14
  end
@@ -6,6 +6,7 @@ class UffizziCore::Deployment::DeleteJob < UffizziCore::ApplicationJob
6
6
  def perform(id)
7
7
  Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{id} DeleteJob")
8
8
 
9
- UffizziCore::ControllerService.delete_deployment(id)
9
+ deployment = UffizziCore::Deployment.find(id)
10
+ UffizziCore::ControllerService.delete_namespace(deployment)
10
11
  end
11
12
  end
@@ -27,7 +27,7 @@ class UffizziCore::Deployment::DeployContainersJob < UffizziCore::ApplicationJob
27
27
  return
28
28
  end
29
29
 
30
- raise UffizziCore::DeploymentNotFoundError, id unless UffizziCore::ControllerService.deployment_exists?(deployment)
30
+ raise UffizziCore::DeploymentNotFoundError, id unless UffizziCore::ControllerService.namespace_exists?(deployment)
31
31
 
32
32
  UffizziCore::DeploymentService.deploy_containers(deployment, repeated)
33
33
  end
@@ -29,7 +29,7 @@ class UffizziCore::Deployment::UpdateCredentialJob < UffizziCore::ApplicationJob
29
29
  return
30
30
  end
31
31
 
32
- unless UffizziCore::ControllerService.deployment_exists?(deployment)
32
+ unless UffizziCore::ControllerService.namespace_exists?(deployment)
33
33
  raise UffizziCore::DeploymentNotFoundError,
34
34
  deployment_id
35
35
  end
@@ -23,6 +23,7 @@ module UffizziCore::Concerns::Models::Account
23
23
  has_many :projects, dependent: :destroy
24
24
  has_many :deployments, through: :projects
25
25
  has_many :payments, dependent: :destroy
26
+ has_many :clusters, through: :projects
26
27
 
27
28
  aasm(:sso_state) do
28
29
  state :connection_not_configured, initial: true
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::Concerns::Models::Cluster
4
+ extend ActiveSupport::Concern
5
+ include UffizziCore::ClusterRepo
6
+
7
+ included do
8
+ include AASM
9
+
10
+ self.table_name = UffizziCore.table_names[:clusters]
11
+
12
+ belongs_to :project, class_name: UffizziCore::Project.name
13
+ belongs_to :deployed_by, class_name: UffizziCore::User.name, foreign_key: :deployed_by_id, optional: true
14
+ validates_uniqueness_of :name, conditions: -> { enabled }, scope: :project_id
15
+ validates :name, presence: true, format: { with: /\A[a-zA-Z0-9-]*\z/ }
16
+
17
+ aasm(:state) do
18
+ state :deploying_namespace, initial: true
19
+ state :failed_deploy_namespace
20
+ state :deploying
21
+ state :deployed
22
+ state :failed
23
+ state :disabled
24
+
25
+ event :start_deploying do
26
+ transitions from: [:deploying_namespace], to: :deploying
27
+ end
28
+
29
+ event :fail_deploy_namespace do
30
+ transitions from: [:deploying_namespace], to: :failed_deploy_namespace
31
+ end
32
+
33
+ event :finish_deploy do
34
+ transitions from: [:deploying], to: :deployed
35
+ end
36
+
37
+ event :fail do
38
+ transitions from: [:deploying], to: :failed
39
+ end
40
+
41
+ event :disable, after: :after_disable do
42
+ transitions from: [:failed_deploy_namespace, :deploying, :deployed, :failed], to: :disabled
43
+ end
44
+ end
45
+
46
+ def after_disable
47
+ UffizziCore::Cluster::DeleteJob.perform_async(id)
48
+ end
49
+
50
+ def namespace
51
+ "cluster-#{id}"
52
+ end
53
+ end
54
+ end
@@ -72,6 +72,10 @@ module UffizziCore::Concerns::Models::Deployment
72
72
  def preview_url
73
73
  "#{subdomain}.#{Settings.app.managed_dns_zone}"
74
74
  end
75
+
76
+ def namespace
77
+ "deployment-#{id}"
78
+ end
75
79
  end
76
80
  # rubocop:enable Metrics/BlockLength
77
81
  end
@@ -22,6 +22,7 @@ module UffizziCore::Concerns::Models::Project
22
22
  has_many :compose_files, dependent: :destroy
23
23
  has_many :secrets, dependent: :destroy, as: :resource
24
24
  has_many :host_volume_files, dependent: :destroy
25
+ has_many :clusters, dependent: :destroy
25
26
 
26
27
  validates :name, presence: true, uniqueness: { scope: :account, message: 'Name already exists' }
27
28
  validates :slug, presence: true, uniqueness: { message: 'Project slug already taken' }
@@ -20,6 +20,7 @@ module UffizziCore::Concerns::Models::User
20
20
  has_many :user_projects, dependent: :destroy
21
21
  has_many :projects, through: :user_projects
22
22
  has_many :deployments, class_name: UffizziCore::Deployment.name, foreign_key: :deployed_by_id, dependent: :nullify
23
+ has_many :clusters, foreign_key: :deployed_by_id
23
24
 
24
25
  has_one_attached :avatar
25
26
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cluster < ApplicationRecord
4
+ include UffizziCore::Concerns::Models::Cluster
5
+ end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Api::Cli::V1::Accounts::ProjectsPolicy < UffizziCore::ApplicationPolicy
4
+ def index?
5
+ context.user_access_module.any_access_to_account?(context.user, context.account)
6
+ end
7
+
4
8
  def create?
5
9
  context.user_access_module.admin_or_developer_access_to_account?(context.user, context.account)
6
10
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::AccountsPolicy < UffizziCore::ApplicationPolicy
4
+ def index?
5
+ context.user.present?
6
+ end
7
+
8
+ def show?
9
+ context.user_access_module.any_access_to_account?(context.user, context.account)
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::ClustersPolicy < UffizziCore::ApplicationPolicy
4
+ def index?
5
+ context.user_access_module.any_access_to_project?(context.user, context.project)
6
+ end
7
+
8
+ def show?
9
+ context.user_access_module.any_access_to_project?(context.user, context.project)
10
+ end
11
+
12
+ def create?
13
+ context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
14
+ end
15
+
16
+ def destroy?
17
+ context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
18
+ end
19
+ end
@@ -6,5 +6,6 @@ module UffizziCore::AccountRepo
6
6
  included do
7
7
  scope :by_kind, ->(kind) { where(kind: kind) }
8
8
  scope :personal, -> { by_kind(UffizziCore::Account.kind.personal) }
9
+ scope :organizational, -> { by_kind(UffizziCore::Account.kind.organizational) }
9
10
  end
10
11
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ClusterRepo
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ scope :deployed, -> { where(state: UffizziCore::Cluster::STATE_DEPLOYED) }
8
+ scope :enabled, -> { where.not(state: UffizziCore::Cluster::STATE_DISABLED) }
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::AccountSerializer < UffizziCore::BaseSerializer
4
+ type :account
5
+
6
+ has_many :projects
7
+
8
+ attributes :id, :name
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::ClusterSerializer < UffizziCore::BaseSerializer
4
+ type :cluster
5
+
6
+ attributes :name, :state, :kubeconfig
7
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Controller::CreateCluster::ClusterSerializer < UffizziCore::BaseSerializer
4
+ attributes :name, :manifest, :base_ingress_host
5
+
6
+ def base_ingress_host
7
+ Settings.app.managed_dns_zone
8
+ end
9
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ClusterService
4
+ class << self
5
+ def start_deploy(cluster)
6
+ UffizziCore::Cluster::DeployJob.perform_async(cluster.id)
7
+ end
8
+
9
+ def deploy_cluster(cluster)
10
+ begin
11
+ UffizziCore::ControllerService.create_namespace(cluster)
12
+ rescue UffizziCore::ControllerClient::ConnectionError
13
+ return cluster.fail_deploy_namespace!
14
+ end
15
+
16
+ cluster.start_deploying!
17
+
18
+ begin
19
+ UffizziCore::ControllerService.create_cluster(cluster)
20
+ rescue UffizziCore::ControllerClient::ConnectionError
21
+ return cluster.fail!
22
+ end
23
+
24
+ UffizziCore::Cluster::ManageDeployingJob.perform_in(5.seconds, cluster.id)
25
+ end
26
+
27
+ def manage_deploying(cluster, try)
28
+ return if cluster.disabled?
29
+ return cluster.fail! if try > Settings.vcluster.max_creation_retry_count
30
+
31
+ deployed_cluster = UffizziCore::ControllerService.show_cluster(cluster)
32
+
33
+ if deployed_cluster.status.ready && deployed_cluster.status.kube_config.present?
34
+ cluster.finish_deploy
35
+ cluster.kubeconfig = deployed_cluster.status.kube_config
36
+ cluster.save!
37
+
38
+ return
39
+ end
40
+
41
+ UffizziCore::Cluster::ManageDeployingJob.perform_in(5.seconds, cluster.id, ++try)
42
+ end
43
+ end
44
+ end
@@ -9,16 +9,7 @@ class UffizziCore::ControllerService
9
9
  config_file: UffizziCore::Controller::ApplyConfigFile::ConfigFileSerializer.new(config_file).as_json,
10
10
  }
11
11
 
12
- controller_client.apply_config_file(deployment_id: deployment.id, config_file_id: config_file.id, body: body)
13
- end
14
-
15
- def create_deployment(deployment)
16
- body = UffizziCore::Controller::CreateDeployment::DeploymentSerializer.new(deployment).as_json
17
- controller_client.create_deployment(deployment_id: deployment.id, body: body)
18
- end
19
-
20
- def delete_deployment(deployment_id)
21
- controller_client.delete_deployment(deployment_id: deployment_id)
12
+ controller_client(deployment).apply_config_file(deployment_id: deployment.id, config_file_id: config_file.id, body: body)
22
13
  end
23
14
 
24
15
  def apply_credential(deployment, credential)
@@ -29,11 +20,11 @@ class UffizziCore::ControllerService
29
20
  options = { image: image }
30
21
 
31
22
  body = UffizziCore::Controller::CreateCredential::CredentialSerializer.new(credential, options).as_json
32
- controller_client.apply_credential(deployment_id: deployment.id, body: body)
23
+ controller_client(deployment).apply_credential(deployment_id: deployment.id, body: body)
33
24
  end
34
25
 
35
26
  def delete_credential(deployment, credential)
36
- controller_client.delete_credential(deployment_id: deployment.id, credential_id: credential.id)
27
+ controller_client(deployment).delete_credential(deployment_id: deployment.id, credential_id: credential.id)
37
28
  end
38
29
 
39
30
  def deploy_containers(deployment, containers)
@@ -65,11 +56,11 @@ class UffizziCore::ControllerService
65
56
  body = password_protection_module.add_password_configuration(body, deployment.project_id)
66
57
  end
67
58
 
68
- controller_client.deploy_containers(deployment_id: deployment.id, body: body)
59
+ controller_client(deployment).deploy_containers(deployment_id: deployment.id, body: body)
69
60
  end
70
61
 
71
- def deployment_exists?(deployment)
72
- controller_client.deployment(deployment_id: deployment.id).code == 200
62
+ def namespace_exists?(deployable)
63
+ controller_client(deployable).namespace(namespace: deployable.namespace).code == 200
73
64
  end
74
65
 
75
66
  def fetch_deployment_events(deployment)
@@ -77,22 +68,53 @@ class UffizziCore::ControllerService
77
68
  end
78
69
 
79
70
  def fetch_pods(deployment)
80
- pods = controller_client.deployment_containers(deployment_id: deployment.id).result || []
71
+ pods = controller_client(deployment).deployment_containers(deployment_id: deployment.id).result || []
81
72
  pods.filter { |pod| pod.metadata.name.start_with?(Settings.controller.namespace_prefix) }
82
73
  end
83
74
 
84
- def fetch_namespace(deployment)
85
- controller_client.deployment(deployment_id: deployment.id).result || nil
75
+ def fetch_namespace(deployable)
76
+ controller_client(deployable).namespace(namespace: deployable.namespace).result || nil
77
+ end
78
+
79
+ def create_namespace(deployable)
80
+ body = { namespace: deployable.namespace }
81
+ controller_client(deployable).create_namespace(body: body).result || nil
82
+ end
83
+
84
+ def delete_namespace(deployable)
85
+ controller_client(deployable).delete_namespace(namespace: deployable.namespace)
86
+ end
87
+
88
+ def create_cluster(cluster)
89
+ body = UffizziCore::Controller::CreateCluster::ClusterSerializer.new(cluster).as_json
90
+ controller_client(cluster).create_cluster(namespace: cluster.namespace, body: body).result
91
+ end
92
+
93
+ def show_cluster(cluster)
94
+ controller_client(cluster).show_cluster(namespace: cluster.namespace, name: cluster.name).result
95
+ end
96
+
97
+ def delete_cluster(cluster)
98
+ controller_client(cluster).delete_cluster(namespace: cluster.namespace)
86
99
  end
87
100
 
88
101
  private
89
102
 
90
103
  def request_events(deployment)
91
- controller_client.deployment_containers_events(deployment_id: deployment.id)
104
+ controller_client(deployment).deployment_containers_events(deployment_id: deployment.id)
92
105
  end
93
106
 
94
- def controller_client
95
- UffizziCore::ControllerClient.new
107
+ def controller_client(deployable)
108
+ settings = case deployable
109
+ when UffizziCore::Deployment
110
+ Settings.controller
111
+ when UffizziCore::Cluster
112
+ Settings.vcluster_controller
113
+ else
114
+ raise StandardError, "Deployable #{deployable.class.name} undefined"
115
+ end
116
+
117
+ UffizziCore::ControllerClient.new(settings)
96
118
  end
97
119
  end
98
120
  end
@@ -37,7 +37,7 @@ class UffizziCore::LogsService
37
37
  end
38
38
 
39
39
  def controller_client
40
- UffizziCore::ControllerClient.new
40
+ UffizziCore::ControllerClient.new(Settings.controller)
41
41
  end
42
42
  end
43
43
  end
data/config/routes.rb CHANGED
@@ -10,6 +10,7 @@ UffizziCore::Engine.routes.draw do
10
10
  resources :projects, only: ['index', 'show', 'destroy'], param: :slug do
11
11
  scope module: :projects do
12
12
  resource :compose_file, only: ['show', 'create', 'destroy']
13
+ resources :clusters, only: [:index, :create, :show, :destroy], param: :name
13
14
  resources :deployments, only: ['index', 'show', 'create', 'destroy', 'update'] do
14
15
  post :deploy_containers, on: :member
15
16
  scope module: :deployments do
@@ -41,9 +42,11 @@ UffizziCore::Engine.routes.draw do
41
42
  resource :session, only: ['create']
42
43
  end
43
44
 
44
- resources :accounts, only: [] do
45
+ resources :accounts, only: ['show'], param: :name
46
+
47
+ resources :accounts, only: ['index'] do
45
48
  scope module: :accounts do
46
- resources :projects, only: ['create']
49
+ resources :projects, only: ['index', 'create']
47
50
  resources :credentials, only: ['index', 'create', 'update', 'destroy'], param: :type do
48
51
  member do
49
52
  get :check_credential
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateClusters < ActiveRecord::Migration[6.1]
4
+ def change
5
+ create_table('uffizzi_core_clusters', force: :cascade) do |t|
6
+ t.references :project, null: false,
7
+ foreign_key: true,
8
+ index: { name: :index_cluster_on_project_id },
9
+ foreign_key: { to_table: :uffizzi_core_projects }
10
+ t.bigint 'deployed_by_id', foreign_key: true
11
+ t.string 'state'
12
+ t.string 'name'
13
+ t.text 'manifest'
14
+ t.text 'kubeconfig'
15
+
16
+ t.timestamps
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UffizziCore
4
- VERSION = '2.1.29'
4
+ VERSION = '2.2.0'
5
5
  end
data/lib/uffizzi_core.rb CHANGED
@@ -35,6 +35,7 @@ module UffizziCore
35
35
  accounts: :uffizzi_core_accounts,
36
36
  activity_items: :uffizzi_core_activity_items,
37
37
  builds: :uffizzi_core_builds,
38
+ clusters: :uffizzi_core_clusters,
38
39
  comments: :uffizzi_core_comments,
39
40
  compose_files: :uffizzi_core_compose_files,
40
41
  config_files: :uffizzi_core_config_files,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uffizzi_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.29
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Thurman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-06-21 00:00:00.000000000 Z
12
+ date: 2023-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aasm
@@ -762,6 +762,7 @@ files:
762
762
  - app/contexts/uffizzi_core/base_context.rb
763
763
  - app/contexts/uffizzi_core/project_context.rb
764
764
  - app/contexts/uffizzi_core/webhooks_context.rb
765
+ - app/controller_modules/uffizzi_core/api/cli/v1/projects/clusters_controller_module.rb
765
766
  - app/controller_modules/uffizzi_core/api/cli/v1/projects/deployments_controller_module.rb
766
767
  - app/controller_modules/uffizzi_core/api/cli/v1/projects_controller_module.rb
767
768
  - app/controllers/concerns/uffizzi_core/auth_management.rb
@@ -770,10 +771,12 @@ files:
770
771
  - app/controllers/uffizzi_core/api/cli/v1/accounts/application_controller.rb
771
772
  - app/controllers/uffizzi_core/api/cli/v1/accounts/credentials_controller.rb
772
773
  - app/controllers/uffizzi_core/api/cli/v1/accounts/projects_controller.rb
774
+ - app/controllers/uffizzi_core/api/cli/v1/accounts_controller.rb
773
775
  - app/controllers/uffizzi_core/api/cli/v1/application_controller.rb
774
776
  - app/controllers/uffizzi_core/api/cli/v1/ci/application_controller.rb
775
777
  - app/controllers/uffizzi_core/api/cli/v1/ci/sessions_controller.rb
776
778
  - app/controllers/uffizzi_core/api/cli/v1/projects/application_controller.rb
779
+ - app/controllers/uffizzi_core/api/cli/v1/projects/clusters_controller.rb
777
780
  - app/controllers/uffizzi_core/api/cli/v1/projects/compose_files_controller.rb
778
781
  - app/controllers/uffizzi_core/api/cli/v1/projects/deployments/activity_items_controller.rb
779
782
  - app/controllers/uffizzi_core/api/cli/v1/projects/deployments/application_controller.rb
@@ -798,6 +801,7 @@ files:
798
801
  - app/forms/uffizzi_core/api/cli/v1/account/credential/check_credential_form.rb
799
802
  - app/forms/uffizzi_core/api/cli/v1/account/credential/create_form.rb
800
803
  - app/forms/uffizzi_core/api/cli/v1/account/credential/update_form.rb
804
+ - app/forms/uffizzi_core/api/cli/v1/cluster/create_form.rb
801
805
  - app/forms/uffizzi_core/api/cli/v1/compose_file/check_credentials_form.rb
802
806
  - app/forms/uffizzi_core/api/cli/v1/compose_file/cli_form.rb
803
807
  - app/forms/uffizzi_core/api/cli/v1/compose_file/create_form.rb
@@ -819,6 +823,9 @@ files:
819
823
  - app/jobs/uffizzi_core/account/update_credential_job.rb
820
824
  - app/jobs/uffizzi_core/activity_item/docker/update_digest_job.rb
821
825
  - app/jobs/uffizzi_core/application_job.rb
826
+ - app/jobs/uffizzi_core/cluster/delete_job.rb
827
+ - app/jobs/uffizzi_core/cluster/deploy_job.rb
828
+ - app/jobs/uffizzi_core/cluster/manage_deploying_job.rb
822
829
  - app/jobs/uffizzi_core/config_file/apply_job.rb
823
830
  - app/jobs/uffizzi_core/deployment/create_credential_job.rb
824
831
  - app/jobs/uffizzi_core/deployment/create_credentials_job.rb
@@ -830,6 +837,7 @@ files:
830
837
  - app/jobs/uffizzi_core/deployment/update_credential_job.rb
831
838
  - app/lib/uffizzi_core/concerns/models/account.rb
832
839
  - app/lib/uffizzi_core/concerns/models/activity_item.rb
840
+ - app/lib/uffizzi_core/concerns/models/cluster.rb
833
841
  - app/lib/uffizzi_core/concerns/models/comment.rb
834
842
  - app/lib/uffizzi_core/concerns/models/compose_file.rb
835
843
  - app/lib/uffizzi_core/concerns/models/config_file.rb
@@ -863,6 +871,7 @@ files:
863
871
  - app/models/uffizzi_core/activity_item/github.rb
864
872
  - app/models/uffizzi_core/activity_item/memory_limit.rb
865
873
  - app/models/uffizzi_core/application_record.rb
874
+ - app/models/uffizzi_core/cluster.rb
866
875
  - app/models/uffizzi_core/comment.rb
867
876
  - app/models/uffizzi_core/compose_file.rb
868
877
  - app/models/uffizzi_core/config_file.rb
@@ -903,6 +912,8 @@ files:
903
912
  - app/models/uffizzi_core/user_project.rb
904
913
  - app/policies/uffizzi_core/api/cli/v1/accounts/credentials_policy.rb
905
914
  - app/policies/uffizzi_core/api/cli/v1/accounts/projects_policy.rb
915
+ - app/policies/uffizzi_core/api/cli/v1/accounts_policy.rb
916
+ - app/policies/uffizzi_core/api/cli/v1/projects/clusters_policy.rb
906
917
  - app/policies/uffizzi_core/api/cli/v1/projects/compose_files_policy.rb
907
918
  - app/policies/uffizzi_core/api/cli/v1/projects/deployments/activity_items_policy.rb
908
919
  - app/policies/uffizzi_core/api/cli/v1/projects/deployments/containers_policy.rb
@@ -914,6 +925,7 @@ files:
914
925
  - app/repositories/uffizzi_core/account_repo.rb
915
926
  - app/repositories/uffizzi_core/activity_item_repo.rb
916
927
  - app/repositories/uffizzi_core/basic_order_repo.rb
928
+ - app/repositories/uffizzi_core/cluster_repo.rb
917
929
  - app/repositories/uffizzi_core/comment_repo.rb
918
930
  - app/repositories/uffizzi_core/compose_file_repo.rb
919
931
  - app/repositories/uffizzi_core/config_file_repo.rb
@@ -931,12 +943,14 @@ files:
931
943
  - app/repositories/uffizzi_core/usage_repo.rb
932
944
  - app/repositories/uffizzi_core/user_repo.rb
933
945
  - app/responders/uffizzi_core/json_responder.rb
946
+ - app/serializers/uffizzi_core/api/cli/v1/account_serializer.rb
934
947
  - app/serializers/uffizzi_core/api/cli/v1/accounts/credential_serializer.rb
935
948
  - app/serializers/uffizzi_core/api/cli/v1/accounts/project_serializer.rb
936
949
  - app/serializers/uffizzi_core/api/cli/v1/project_serializer.rb
937
950
  - app/serializers/uffizzi_core/api/cli/v1/project_serializer/account_serializer.rb
938
951
  - app/serializers/uffizzi_core/api/cli/v1/project_serializer/compose_file_serializer.rb
939
952
  - app/serializers/uffizzi_core/api/cli/v1/project_serializer/deployment_serializer.rb
953
+ - app/serializers/uffizzi_core/api/cli/v1/projects/cluster_serializer.rb
940
954
  - app/serializers/uffizzi_core/api/cli/v1/projects/compose_file_serializer.rb
941
955
  - app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer.rb
942
956
  - app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb
@@ -953,6 +967,7 @@ files:
953
967
  - app/serializers/uffizzi_core/api/cli/v1/user_serializer/account_serializer.rb
954
968
  - app/serializers/uffizzi_core/base_serializer.rb
955
969
  - app/serializers/uffizzi_core/controller/apply_config_file/config_file_serializer.rb
970
+ - app/serializers/uffizzi_core/controller/create_cluster/cluster_serializer.rb
956
971
  - app/serializers/uffizzi_core/controller/create_credential/credential_serializer.rb
957
972
  - app/serializers/uffizzi_core/controller/create_deployment/deployment_serializer.rb
958
973
  - app/serializers/uffizzi_core/controller/deploy_containers/compose_file_serializer.rb
@@ -964,6 +979,7 @@ files:
964
979
  - app/serializers/uffizzi_core/controller/deploy_containers/host_volume_file_serializer.rb
965
980
  - app/services/uffizzi_core/account_service.rb
966
981
  - app/services/uffizzi_core/activity_item_service.rb
982
+ - app/services/uffizzi_core/cluster_service.rb
967
983
  - app/services/uffizzi_core/compose_file/builders/container_builder_service.rb
968
984
  - app/services/uffizzi_core/compose_file/builders/container_config_files_builder_service.rb
969
985
  - app/services/uffizzi_core/compose_file/builders/container_host_volume_files_builder_service.rb
@@ -1043,6 +1059,7 @@ files:
1043
1059
  - db/migrate/20230111000000_add_state_to_memberships.rb
1044
1060
  - db/migrate/20230306142513_add_last_deploy_at_to_deployments.rb
1045
1061
  - db/migrate/20230406154451_add_full_image_name_to_container.rb
1062
+ - db/migrate/20230613101901_create_clusters.rb
1046
1063
  - db/seeds.rb
1047
1064
  - lib/tasks/uffizzi_core_tasks.rake
1048
1065
  - lib/uffizzi_core.rb