uffizzi_core 2.2.23 → 2.2.25

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 173a91720da5a1063dd5db63c18c0232a5621dd68b77a120b81341aafba4c2a8
4
- data.tar.gz: 03f50a4669fe8688f0e3d280b0589c5123f39ad710cf24d09bdaea19235cc9d3
3
+ metadata.gz: 70847fae8bc28249be5879f8496e7436e05079077dc23ad53394d08676158be6
4
+ data.tar.gz: 2ac3e45d651e069f5e11b69b022efa285c5f0c0f176fb5a17c0bc58c3d4dad88
5
5
  SHA512:
6
- metadata.gz: 75934782b7e324fa161b9968efe45454e3483f791980ba85b8342a8c93ce49951483d06250154fdba2bf212aa8ea5794531d90afcf1039825f4d4ddfc8917c82
7
- data.tar.gz: a5c73682a9152c98c1801379c91c72fbf66212b429d9412d240731f80181d21b91349cdda6e02d51e5616a1968ebb5ea5c99baec830aa1e3fd7cd3e441078b15
6
+ metadata.gz: c128f0afe2384d0763597a9bbc3977748282a454a7d6396680b6f6642f00aa3b6ea32ee0d6c1125846338fec29e8ec02a0bf135d16943a3a2f3ff1f7caf5e797
7
+ data.tar.gz: 8a0877404587daa608bb636f6500c03578d711ab7cb8e58db97ed9cb663114374cef6f8a619f6dbc9a5c0c0ac3fe4478bf559f53df1c3b6f266d3820f7661f3c
@@ -78,6 +78,10 @@ class UffizziCore::ControllerClient
78
78
  get("/namespaces/#{namespace}/cluster/#{name}")
79
79
  end
80
80
 
81
+ def patch_cluster(name:, namespace:, body:)
82
+ patch("/namespaces/#{namespace}/cluster/#{name}", body)
83
+ end
84
+
81
85
  private
82
86
 
83
87
  def get(url, params = {})
@@ -88,6 +92,10 @@ class UffizziCore::ControllerClient
88
92
  make_request(:post, url, params)
89
93
  end
90
94
 
95
+ def patch(url, params = {})
96
+ make_request(:patch, url, params)
97
+ end
98
+
91
99
  def make_request(method, url, params)
92
100
  response = connection.send(method, url, params)
93
101
  body = response.body
@@ -11,13 +11,18 @@ class UffizziCore::Api::Cli::V1::Projects::ClustersController < UffizziCore::Api
11
11
  clusters = resource_project.clusters.enabled
12
12
  return respond_with clusters if request_by_admin? || valid_request_from_ci_workflow?
13
13
 
14
- respond_with clusters.deployed_by_user(current_user)
14
+ respond_with clusters.deployed_by_user(current_user), each_serializer: UffizziCore::Api::Cli::V1::Projects::ShortClusterSerializer
15
15
  end
16
16
 
17
17
  def create
18
+ version = cluster_params[:k8s_version]
19
+ kubernetes_distribution = find_kubernetes_distribution(version)
20
+ return render_distribution_version_error(version) if kubernetes_distribution.blank?
21
+
18
22
  cluster_form = UffizziCore::Api::Cli::V1::Cluster::CreateForm.new(cluster_params)
19
23
  cluster_form.project = resource_project
20
24
  cluster_form.deployed_by = current_user
25
+ cluster_form.kubernetes_distribution = kubernetes_distribution
21
26
  return respond_with cluster_form unless cluster_form.save
22
27
 
23
28
  UffizziCore::ClusterService.start_deploy(cluster_form)
@@ -25,6 +30,32 @@ class UffizziCore::Api::Cli::V1::Projects::ClustersController < UffizziCore::Api
25
30
  respond_with cluster_form
26
31
  end
27
32
 
33
+ def scale_down
34
+ if resource_cluster.deployed?
35
+ UffizziCore::ClusterService.scale_down!(resource_cluster)
36
+ return respond_with resource_cluster
37
+ end
38
+
39
+ return render_scale_error(I18n.t('cluster.already_asleep', name: resource_cluster.name)) if resource_cluster.scaled_down?
40
+
41
+ if resource_cluster.deploying_namespace? || resource_cluster.deploying?
42
+ render_scale_error(I18n.t('cluster.deploy_in_process', name: resource_cluster.name))
43
+ end
44
+ rescue AASM::InvalidTransition, UffizziCore::ClusterScaleError => e
45
+ render_scale_error(e.message)
46
+ end
47
+
48
+ def scale_up
49
+ if resource_cluster.scaled_down?
50
+ UffizziCore::ClusterService.scale_up!(resource_cluster)
51
+ return respond_with resource_cluster
52
+ end
53
+
54
+ return render_scale_error(I18n.t('cluster.already_awake', name: resource_cluster.name)) if resource_cluster.deployed?
55
+ rescue AASM::InvalidTransition, UffizziCore::ClusterScaleError => e
56
+ render_scale_error(e.message)
57
+ end
58
+
28
59
  def show
29
60
  respond_with resource_cluster
30
61
  end
@@ -57,4 +88,20 @@ class UffizziCore::Api::Cli::V1::Projects::ClustersController < UffizziCore::Api
57
88
  def cluster_params
58
89
  params.require(:cluster)
59
90
  end
91
+
92
+ def render_scale_error(message)
93
+ render json: { errors: { state: [message] } }, status: :unprocessable_entity
94
+ end
95
+
96
+ def find_kubernetes_distribution(version)
97
+ return UffizziCore::KubernetesDistribution.default if version.blank?
98
+
99
+ UffizziCore::KubernetesDistribution.find_by(version: version)
100
+ end
101
+
102
+ def render_distribution_version_error(version)
103
+ available_versions = UffizziCore::KubernetesDistribution.pluck(:version).join(', ')
104
+ message = I18n.t('kubernetes_distribution.not_available', version: version, available_versions: available_versions)
105
+ render json: { errors: { kubernetes_distribution: [message] } }, status: :unprocessable_entity
106
+ end
60
107
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ClusterScaleError < StandardError
4
+ def initialize(action)
5
+ message = I18n.t('cluster.scaling_failed', action: action)
6
+
7
+ super(message)
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cluster::ManageScalingDownJob < UffizziCore::ApplicationJob
4
+ sidekiq_options queue: :clusters, retry: Settings.default_job_retry_count
5
+
6
+ def perform(id)
7
+ cluster = UffizziCore::Cluster.find(id)
8
+
9
+ UffizziCore::ClusterService.manage_scale_down(cluster)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cluster::ManageScalingUpJob < UffizziCore::ApplicationJob
4
+ sidekiq_options queue: :clusters, retry: Settings.default_job_retry_count
5
+
6
+ def perform(id, try = 1)
7
+ cluster = UffizziCore::Cluster.find(id)
8
+
9
+ UffizziCore::ClusterService.manage_scale_up(cluster, try)
10
+ end
11
+ end
@@ -6,6 +6,7 @@ module UffizziCore::Concerns::Models::Cluster
6
6
 
7
7
  NAMESPACE_PREFIX = 'c'
8
8
 
9
+ # rubocop:disable Metrics/BlockLength
9
10
  included do
10
11
  include AASM
11
12
  extend Enumerize
@@ -20,12 +21,17 @@ module UffizziCore::Concerns::Models::Cluster
20
21
  enumerize :creation_source, in: UffizziCore.cluster_creation_sources, scope: true, predicates: true
21
22
  attribute :creation_source, :string, default: :manual
22
23
  validates :creation_source, presence: true
24
+ belongs_to :kubernetes_distribution, optional: true
23
25
 
24
26
  aasm(:state) do
25
27
  state :deploying_namespace, initial: true
26
28
  state :failed_deploy_namespace
27
29
  state :deploying
28
30
  state :deployed
31
+ state :scaling_down
32
+ state :scaled_down
33
+ state :scaling_up
34
+ state :failed_scale_up
29
35
  state :failed
30
36
  state :disabled
31
37
 
@@ -41,12 +47,40 @@ module UffizziCore::Concerns::Models::Cluster
41
47
  transitions from: [:deploying], to: :deployed
42
48
  end
43
49
 
50
+ event :start_scaling_down do
51
+ transitions from: [:deployed], to: :scaling_down
52
+ end
53
+
54
+ event :scale_down do
55
+ transitions from: [:scaling_down], to: :scaled_down
56
+ end
57
+
58
+ event :start_scaling_up do
59
+ transitions from: [:scaled_down, :failed_scale_up], to: :scaling_up
60
+ end
61
+
62
+ event :scale_up do
63
+ transitions from: [:scaling_up], to: :deployed
64
+ end
65
+
66
+ event :fail_scale_up do
67
+ transitions from: [:scaling_up], to: :failed_scale_up
68
+ end
69
+
44
70
  event :fail do
45
71
  transitions from: [:deploying], to: :failed
46
72
  end
47
73
 
48
74
  event :disable, after: :after_disable do
49
- transitions from: [:deploying_namespace, :failed_deploy_namespace, :deploying, :deployed, :failed], to: :disabled
75
+ transitions from: [
76
+ :deploying_namespace,
77
+ :failed_deploy_namespace,
78
+ :deploying,
79
+ :deployed,
80
+ :scaling_down,
81
+ :scaled_down,
82
+ :failed,
83
+ ], to: :disabled
50
84
  end
51
85
  end
52
86
 
@@ -58,4 +92,5 @@ module UffizziCore::Concerns::Models::Cluster
58
92
  [NAMESPACE_PREFIX, id].join
59
93
  end
60
94
  end
95
+ # rubocop:enable Metrics/BlockLength
61
96
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::Concerns::Models::KubernetesDistribution
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ self.table_name = UffizziCore.table_names[:kubernetes_distributions]
8
+
9
+ has_many :clusters
10
+
11
+ def self.default
12
+ find_by(default: true)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::KubernetesDistribution < UffizziCore::ApplicationRecord
4
+ include UffizziCore::Concerns::Models::KubernetesDistribution
5
+ end
@@ -13,6 +13,14 @@ class UffizziCore::Api::Cli::V1::Projects::ClustersPolicy < UffizziCore::Applica
13
13
  context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
14
14
  end
15
15
 
16
+ def scale_down?
17
+ context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
18
+ end
19
+
20
+ def scale_up?
21
+ context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
22
+ end
23
+
16
24
  def destroy?
17
25
  context.user_access_module.admin_or_developer_access_to_project?(context.user, context.project)
18
26
  end
@@ -3,5 +3,9 @@
3
3
  class UffizziCore::Api::Cli::V1::Projects::ClusterSerializer < UffizziCore::BaseSerializer
4
4
  type :cluster
5
5
 
6
- attributes :id, :name, :state, :kubeconfig, :created_at, :host
6
+ attributes :id, :name, :state, :kubeconfig, :created_at, :host, :k8s_version
7
+
8
+ def k8s_version
9
+ object.kubernetes_distribution&.version || UffizziCore::KubernetesDistribution.default.version
10
+ end
7
11
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::ShortClusterSerializer < UffizziCore::BaseSerializer
4
+ type :cluster
5
+
6
+ attributes :id, :name
7
+ end
@@ -4,11 +4,25 @@ class UffizziCore::Controller::CreateCluster::ClusterSerializer < UffizziCore::B
4
4
  include UffizziCore::DependencyInjectionConcern
5
5
  include_module_if_exists('UffizziCore::Controller::CreateCluster::ClusterSerializerModule')
6
6
 
7
- attributes :name, :manifest, :base_ingress_host
7
+ attributes :name, :manifest, :base_ingress_host, :distro, :image
8
8
 
9
9
  def base_ingress_host
10
10
  managed_dns_zone = controller_settings_service.vcluster(object).managed_dns_zone
11
11
 
12
12
  [object.namespace, managed_dns_zone].join('.')
13
13
  end
14
+
15
+ def image
16
+ kubernetes_distribution.image
17
+ end
18
+
19
+ def distro
20
+ kubernetes_distribution.distro
21
+ end
22
+
23
+ private
24
+
25
+ def kubernetes_distribution
26
+ @kubernetes_distribution ||= object.kubernetes_distribution
27
+ end
14
28
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Controller::UpdateCluster::ClusterSerializer < UffizziCore::BaseSerializer
4
+ include UffizziCore::DependencyInjectionConcern
5
+ include_module_if_exists('UffizziCore::Controller::UpdateCluster::ClusterSerializerModule')
6
+
7
+ attributes :name, :manifest, :base_ingress_host
8
+
9
+ def base_ingress_host
10
+ managed_dns_zone = controller_settings_service.vcluster(object).managed_dns_zone
11
+
12
+ [object.namespace, managed_dns_zone].join('.')
13
+ end
14
+ end
@@ -24,6 +24,32 @@ class UffizziCore::ClusterService
24
24
  UffizziCore::Cluster::ManageDeployingJob.perform_in(5.seconds, cluster.id)
25
25
  end
26
26
 
27
+ def scale_up!(cluster)
28
+ cluster.start_scaling_up!
29
+ UffizziCore::ControllerService.patch_cluster(cluster, sleep: false)
30
+ UffizziCore::Cluster::ManageScalingUpJob.perform_in(5.seconds, cluster.id)
31
+ end
32
+
33
+ def manage_scale_up(cluster, try)
34
+ return cluster.fail_scale_up! if try > Settings.vcluster.max_scale_up_retry_count
35
+ return cluster.scale_up! if ready?(cluster)
36
+
37
+ UffizziCore::Cluster::ManageScalingUpJob.perform_in(5.seconds, cluster.id, ++try)
38
+ end
39
+
40
+ def scale_down!(cluster)
41
+ cluster.start_scaling_down!
42
+ UffizziCore::ControllerService.patch_cluster(cluster, sleep: true)
43
+
44
+ UffizziCore::Cluster::ManageScalingDownJob.perform_in(5.seconds, cluster.id)
45
+ end
46
+
47
+ def manage_scale_down(cluster)
48
+ return cluster.scale_down! unless awake?(cluster)
49
+
50
+ UffizziCore::Cluster::ManageScalingDownJob.perform_in(5.seconds, cluster.id)
51
+ end
52
+
27
53
  def manage_deploying(cluster, try)
28
54
  return if cluster.disabled?
29
55
  return cluster.fail! if try > Settings.vcluster.max_creation_retry_count
@@ -41,5 +67,19 @@ class UffizziCore::ClusterService
41
67
 
42
68
  UffizziCore::Cluster::ManageDeployingJob.perform_in(5.seconds, cluster.id, ++try)
43
69
  end
70
+
71
+ private
72
+
73
+ def awake?(cluster)
74
+ data = UffizziCore::ControllerService.show_cluster(cluster)
75
+
76
+ !data.status.sleep
77
+ end
78
+
79
+ def ready?(cluster)
80
+ data = UffizziCore::ControllerService.show_cluster(cluster)
81
+
82
+ data.status.ready
83
+ end
44
84
  end
45
85
  end
@@ -110,6 +110,13 @@ class UffizziCore::ControllerService
110
110
  controller_client(cluster).delete_cluster(namespace: cluster.namespace)
111
111
  end
112
112
 
113
+ def patch_cluster(cluster, sleep:)
114
+ body = UffizziCore::Controller::UpdateCluster::ClusterSerializer.new(cluster).as_json
115
+ body[:sleep] = sleep
116
+
117
+ controller_client(cluster).patch_cluster(name: cluster.name, namespace: cluster.namespace, body: body)
118
+ end
119
+
113
120
  private
114
121
 
115
122
  def check_any_container_has_public_port(containers)
@@ -83,11 +83,20 @@ en:
83
83
  deployment:
84
84
  invalid_state: Preview with ID deployment-%{id} %{state}
85
85
  already_exists: An active deployment already exists
86
+
87
+ cluster:
88
+ already_asleep: The cluster %{name} is already asleep.
89
+ already_awake: The cluster %{name} is already awake.
90
+ scaling_failed: Failed to %{action} cluster.
91
+ deploy_in_process: Please wait until the cluster %{name} is deployed.
86
92
 
87
93
  session:
88
94
  unsupported_login_type: This type of login is not supported
89
95
  unauthorized: Unauthorized
90
96
 
97
+ kubernetes_distribution:
98
+ not_available: "The k8s version %{version} is not supported. Available version are: %{available_versions}."
99
+
91
100
  enumerize:
92
101
  credential:
93
102
  type:
data/config/routes.rb CHANGED
@@ -10,7 +10,12 @@ 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
+ resources :clusters, only: [:index, :create, :show, :destroy], param: :name do
14
+ member do
15
+ put :scale_down
16
+ put :scale_up
17
+ end
18
+ end
14
19
  resources :deployments, only: ['index', 'show', 'create', 'destroy', 'update'] do
15
20
  post :deploy_containers, on: :member
16
21
  scope module: :deployments do
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateUffizziCoreKubernetesDistributions < ActiveRecord::Migration[6.1]
4
+ def change
5
+ create_table :uffizzi_core_kubernetes_distributions do |t|
6
+ t.string :version
7
+ t.string :distro
8
+ t.string :image
9
+ t.boolean :default, default: false
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddKubernetesDistributionIdToUffizziCoreClusters < ActiveRecord::Migration[6.1]
4
+ def change
5
+ add_column(:uffizzi_core_clusters, :kubernetes_distribution_id, :integer, foreign_key: true)
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UffizziCore
4
- VERSION = '2.2.23'
4
+ VERSION = '2.2.25'
5
5
  end
data/lib/uffizzi_core.rb CHANGED
@@ -66,6 +66,7 @@ module UffizziCore
66
66
  host_volume_files: :uffizzi_core_host_volume_files,
67
67
  container_host_volume_files: :uffizzi_core_container_host_volume_files,
68
68
  deployment_events: :uffizzi_core_deployment_events,
69
+ kubernetes_distributions: :uffizzi_core_kubernetes_distributions,
69
70
  }
70
71
  mattr_accessor :user_creation_sources, default: [:system, :online_registration, :google, :sso]
71
72
  mattr_accessor :user_project_roles, default: [:admin, :developer, :viewer]
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.2.23
4
+ version: 2.2.25
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-10-06 00:00:00.000000000 Z
12
+ date: 2023-10-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aasm
@@ -804,6 +804,7 @@ files:
804
804
  - app/controllers/uffizzi_core/api/cli/v1/projects_controller.rb
805
805
  - app/controllers/uffizzi_core/api/cli/v1/sessions_controller.rb
806
806
  - app/controllers/uffizzi_core/application_controller.rb
807
+ - app/errors/uffizzi_core/cluster_scale_error.rb
807
808
  - app/errors/uffizzi_core/compose_file/build_error.rb
808
809
  - app/errors/uffizzi_core/compose_file/credential_error.rb
809
810
  - app/errors/uffizzi_core/compose_file/parse_error.rb
@@ -841,6 +842,8 @@ files:
841
842
  - app/jobs/uffizzi_core/cluster/delete_job.rb
842
843
  - app/jobs/uffizzi_core/cluster/deploy_job.rb
843
844
  - app/jobs/uffizzi_core/cluster/manage_deploying_job.rb
845
+ - app/jobs/uffizzi_core/cluster/manage_scaling_down_job.rb
846
+ - app/jobs/uffizzi_core/cluster/manage_scaling_up_job.rb
844
847
  - app/jobs/uffizzi_core/config_file/apply_job.rb
845
848
  - app/jobs/uffizzi_core/deployment/create_credential_job.rb
846
849
  - app/jobs/uffizzi_core/deployment/create_credentials_job.rb
@@ -865,6 +868,7 @@ files:
865
868
  - app/lib/uffizzi_core/concerns/models/deployment_event.rb
866
869
  - app/lib/uffizzi_core/concerns/models/event.rb
867
870
  - app/lib/uffizzi_core/concerns/models/host_volume_file.rb
871
+ - app/lib/uffizzi_core/concerns/models/kubernetes_distribution.rb
868
872
  - app/lib/uffizzi_core/concerns/models/membership.rb
869
873
  - app/lib/uffizzi_core/concerns/models/payment.rb
870
874
  - app/lib/uffizzi_core/concerns/models/price.rb
@@ -909,6 +913,7 @@ files:
909
913
  - app/models/uffizzi_core/deployment_event.rb
910
914
  - app/models/uffizzi_core/event.rb
911
915
  - app/models/uffizzi_core/host_volume_file.rb
916
+ - app/models/uffizzi_core/kubernetes_distribution.rb
912
917
  - app/models/uffizzi_core/membership.rb
913
918
  - app/models/uffizzi_core/payment.rb
914
919
  - app/models/uffizzi_core/price.rb
@@ -982,6 +987,7 @@ files:
982
987
  - app/serializers/uffizzi_core/api/cli/v1/projects/deployments_serializer.rb
983
988
  - app/serializers/uffizzi_core/api/cli/v1/projects/deployments_serializer/user_serializer.rb
984
989
  - app/serializers/uffizzi_core/api/cli/v1/projects/secret_serializer.rb
990
+ - app/serializers/uffizzi_core/api/cli/v1/projects/short_cluster_serializer.rb
985
991
  - app/serializers/uffizzi_core/api/cli/v1/short_project_serializer.rb
986
992
  - app/serializers/uffizzi_core/api/cli/v1/user_serializer.rb
987
993
  - app/serializers/uffizzi_core/api/cli/v1/user_serializer/account_serializer.rb
@@ -997,6 +1003,7 @@ files:
997
1003
  - app/serializers/uffizzi_core/controller/deploy_containers/container_serializer/container_host_volume_file_serializer.rb
998
1004
  - app/serializers/uffizzi_core/controller/deploy_containers/credential_serializer.rb
999
1005
  - app/serializers/uffizzi_core/controller/deploy_containers/host_volume_file_serializer.rb
1006
+ - app/serializers/uffizzi_core/controller/update_cluster/cluster_serializer.rb
1000
1007
  - app/services/uffizzi_core/account_service.rb
1001
1008
  - app/services/uffizzi_core/activity_item_service.rb
1002
1009
  - app/services/uffizzi_core/ci_service.rb
@@ -1088,6 +1095,8 @@ files:
1088
1095
  - db/migrate/20230711101901_add_host_to_clusters.rb
1089
1096
  - db/migrate/20230810140316_add_source_to_uffizzi_core_clusters.rb
1090
1097
  - db/migrate/20230824150022_update_name_constraint_to_projects.rb
1098
+ - db/migrate/20231009162719_create_uffizzi_core_kubernetes_distributions.rb
1099
+ - db/migrate/20231009182412_add_kubernetes_distribution_id_to_uffizzi_core_clusters.rb
1091
1100
  - db/seeds.rb
1092
1101
  - lib/tasks/uffizzi_core_tasks.rake
1093
1102
  - lib/uffizzi_core.rb