uffizzi_core 2.0.19 → 2.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/app/clients/uffizzi_core/azure_registry_client.rb +9 -6
  3. data/app/clients/uffizzi_core/container_registry_request_decorator.rb +11 -0
  4. data/app/clients/uffizzi_core/docker_hub_client.rb +12 -9
  5. data/app/clients/uffizzi_core/docker_registry_client.rb +12 -8
  6. data/app/clients/uffizzi_core/github_container_registry_client.rb +17 -11
  7. data/app/clients/uffizzi_core/google_registry_client.rb +9 -6
  8. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers_controller.rb +8 -0
  9. data/app/errors/uffizzi_core/compose_file/build_error.rb +6 -1
  10. data/app/errors/uffizzi_core/compose_file/secrets_error.rb +6 -1
  11. data/app/errors/uffizzi_core/compose_file_error.rb +19 -0
  12. data/app/errors/uffizzi_core/container_registry_error.rb +25 -0
  13. data/app/forms/uffizzi_core/api/cli/v1/compose_file/check_credentials_form.rb +9 -4
  14. data/app/forms/uffizzi_core/api/cli/v1/compose_file/template_form.rb +12 -10
  15. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/containers_policy.rb +4 -0
  16. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb +2 -1
  17. data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +3 -1
  18. data/app/services/uffizzi_core/compose_file/errors_service.rb +8 -0
  19. data/app/services/uffizzi_core/container_registry/azure_service.rb +1 -3
  20. data/app/services/uffizzi_core/container_registry/docker_hub_service.rb +5 -11
  21. data/app/services/uffizzi_core/container_registry/docker_registry_service.rb +2 -2
  22. data/app/services/uffizzi_core/container_registry/github_container_registry_service.rb +1 -9
  23. data/app/services/uffizzi_core/container_registry/google_service.rb +1 -3
  24. data/app/services/uffizzi_core/container_registry_service.rb +2 -0
  25. data/app/services/uffizzi_core/container_service.rb +28 -0
  26. data/config/locales/en.yml +8 -0
  27. data/config/routes.rb +1 -0
  28. data/lib/uffizzi_core/version.rb +1 -1
  29. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56cc9e09a80d239e143e024ca46b35a716ee35ae540543937b2d6bc6828b1cb4
4
- data.tar.gz: f45e872ca5bd8715929214c6837784f582b08e46a5abe1e4cc4ff91b2c400115
3
+ metadata.gz: 9c6052d327892d715fdae978c23f607e4f31ba2829f433bb60e67621da7ace14
4
+ data.tar.gz: c5ce343ecba716c0a92fd206983e126de77949235e2ff4f596557458952b203e
5
5
  SHA512:
6
- metadata.gz: 62a62bf2c4a78e33831cf675a7e4d258d40254018939c907aa3d859a5454f916061de63c92f75382471b81186209507580126a799b8b5fb90beb141bcbd4917d
7
- data.tar.gz: fb5dd99d8253c1f5c12624b511db0d3a1e672d87f15cfb6cf3f16fca2b3880e11a4a67fc32a431c0038141c6295123fa441259a69cd469aa40ef64511cf435b4
6
+ metadata.gz: b4a3168cc3c0c07688bd8fdc9db228f296d2ed79bcc19299414b35f8a108e0ff67049c0604ce1edb976ed0c88f334d0c6fd2146658321d1096086bea57c19037
7
+ data.tar.gz: 869d36425dad9eaac7eee8fecd86c7b56e8d3102af9a2e4249a8ff5af55a047e5fa6d9125fab0835fd13f568d1d322b83f7e900b01bfff0dde4b6024d2834b8d
@@ -25,18 +25,21 @@ class UffizziCore::AzureRegistryClient
25
25
  RequestResult.new(result: response.body)
26
26
  end
27
27
 
28
- def authentificated?
28
+ def authenticated?
29
29
  token.present?
30
30
  end
31
31
 
32
32
  private
33
33
 
34
34
  def build_connection(registry_url, username, password)
35
- Faraday.new(registry_url) do |conn|
36
- conn.request(:basic_auth, username, password)
37
- conn.request(:json)
38
- conn.response(:json)
39
- conn.adapter(Faraday.default_adapter)
35
+ connection = Faraday.new(registry_url) do |faraday|
36
+ faraday.request(:basic_auth, username, password)
37
+ faraday.request(:json)
38
+ faraday.response(:json)
39
+ faraday.response(:raise_error)
40
+ faraday.adapter(Faraday.default_adapter)
40
41
  end
42
+
43
+ connection.extend(UffizziCore::ContainerRegistryRequestDecorator)
41
44
  end
42
45
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ContainerRegistryRequestDecorator
4
+ [:get, :post, :head].each do |method|
5
+ define_method(method) do |url, params_or_body = nil, headers = nil, &block|
6
+ super(url, params_or_body, headers, &block)
7
+ rescue Faraday::ClientError => e
8
+ raise UffizziCore::ContainerRegistryError.new(e.response)
9
+ end
10
+ end
11
+ end
@@ -10,10 +10,10 @@ class UffizziCore::DockerHubClient
10
10
  @credential = credential
11
11
  return unless credential
12
12
 
13
- @jwt = authentificate
13
+ @jwt = authenticate
14
14
  end
15
15
 
16
- def authentificate
16
+ def authenticate
17
17
  params = { username: credential.username, password: credential.password }
18
18
  url = "#{BASE_URL}/v2/users/login/"
19
19
  response = connection.post(url, params)
@@ -42,7 +42,7 @@ class UffizziCore::DockerHubClient
42
42
  end
43
43
 
44
44
  def private_images(account:, page: 1, per_page: 25)
45
- raise NotAuthorizedError if !authentificated? || account.empty?
45
+ raise NotAuthorizedError if !authenticated? || account.empty?
46
46
 
47
47
  url = BASE_URL + "/v2/repositories/#{account}/"
48
48
  params = { page_size: per_page, page: page }
@@ -53,7 +53,7 @@ class UffizziCore::DockerHubClient
53
53
  end
54
54
 
55
55
  def accounts
56
- raise NotAuthorizedError if !authentificated?
56
+ raise NotAuthorizedError if !authenticated?
57
57
 
58
58
  url = "#{BASE_URL}/v2/repositories/namespaces/"
59
59
  response = connection.get(url) do |request|
@@ -96,17 +96,20 @@ class UffizziCore::DockerHubClient
96
96
  RequestResult.new(result: response.body)
97
97
  end
98
98
 
99
- def authentificated?
99
+ def authenticated?
100
100
  jwt.present?
101
101
  end
102
102
 
103
103
  private
104
104
 
105
105
  def build_connection
106
- Faraday.new do |conn|
107
- conn.request(:json)
108
- conn.response(:json)
109
- conn.adapter(Faraday.default_adapter)
106
+ connection = Faraday.new do |faraday|
107
+ faraday.request(:json)
108
+ faraday.response(:json)
109
+ faraday.response(:raise_error)
110
+ faraday.adapter(Faraday.default_adapter)
110
111
  end
112
+
113
+ connection.extend(UffizziCore::ContainerRegistryRequestDecorator)
111
114
  end
112
115
  end
@@ -7,8 +7,9 @@ class UffizziCore::DockerRegistryClient
7
7
  end
8
8
 
9
9
  def authenticated?
10
- response = @connection.head('/v2/')
11
- response.status == 200
10
+ @connection.head('/v2/')
11
+
12
+ true
12
13
  end
13
14
 
14
15
  def manifests(image:, tag:, namespace: nil)
@@ -22,12 +23,15 @@ class UffizziCore::DockerRegistryClient
22
23
  private
23
24
 
24
25
  def build_connection(registry_url, username, password)
25
- Faraday.new(registry_url) do |conn|
26
- conn.request(:basic_auth, username, password) if username.present? && password.present?
27
- conn.request(:json)
28
- conn.response(:json)
29
- conn.response(:follow_redirects)
30
- conn.adapter(Faraday.default_adapter)
26
+ connection = Faraday.new(registry_url) do |faraday|
27
+ faraday.request(:basic_auth, username, password) if username.present? && password.present?
28
+ faraday.request(:json)
29
+ faraday.response(:json)
30
+ faraday.response(:follow_redirects)
31
+ faraday.response(:raise_error)
32
+ faraday.adapter(Faraday.default_adapter)
31
33
  end
34
+
35
+ connection.extend(UffizziCore::ContainerRegistryRequestDecorator)
32
36
  end
33
37
  end
@@ -19,7 +19,7 @@ class UffizziCore::GithubContainerRegistryClient
19
19
  RequestResult.new(result: response.body)
20
20
  end
21
21
 
22
- def authentificated?
22
+ def authenticated?
23
23
  token.present?
24
24
  end
25
25
 
@@ -33,20 +33,26 @@ class UffizziCore::GithubContainerRegistryClient
33
33
  private
34
34
 
35
35
  def connection
36
- Faraday.new(registry_url) do |conn|
37
- conn.request(:basic_auth, @username, @password)
38
- conn.request(:json)
39
- conn.response(:json)
40
- conn.adapter(Faraday.default_adapter)
36
+ connection = Faraday.new(registry_url) do |faraday|
37
+ faraday.request(:basic_auth, @username, @password)
38
+ faraday.request(:json)
39
+ faraday.response(:json)
40
+ faraday.response(:raise_error)
41
+ faraday.adapter(Faraday.default_adapter)
41
42
  end
43
+
44
+ connection.extend(UffizziCore::ContainerRegistryRequestDecorator)
42
45
  end
43
46
 
44
47
  def token_connection
45
- Faraday.new(registry_url) do |conn|
46
- conn.request(:authorization, 'Bearer', token)
47
- conn.request(:json)
48
- conn.response(:json)
49
- conn.adapter(Faraday.default_adapter)
48
+ connection = Faraday.new(registry_url) do |faraday|
49
+ faraday.request(:authorization, 'Bearer', token)
50
+ faraday.request(:json)
51
+ faraday.response(:json)
52
+ faraday.response(:raise_error)
53
+ faraday.adapter(Faraday.default_adapter)
50
54
  end
55
+
56
+ connection.extend(UffizziCore::ContainerRegistryRequestDecorator)
51
57
  end
52
58
  end
@@ -25,18 +25,21 @@ class UffizziCore::GoogleRegistryClient
25
25
  RequestResult.new(result: response.body)
26
26
  end
27
27
 
28
- def authentificated?
28
+ def authenticated?
29
29
  token.present?
30
30
  end
31
31
 
32
32
  private
33
33
 
34
34
  def build_connection(registry_url, username, password)
35
- Faraday.new(registry_url) do |conn|
36
- conn.request(:basic_auth, username, password)
37
- conn.request(:json)
38
- conn.response(:json)
39
- conn.adapter(Faraday.default_adapter)
35
+ connection = Faraday.new(registry_url) do |faraday|
36
+ faraday.request(:basic_auth, username, password)
37
+ faraday.request(:json)
38
+ faraday.response(:json)
39
+ faraday.response(:raise_error)
40
+ faraday.adapter(Faraday.default_adapter)
40
41
  end
42
+
43
+ connection.extend(UffizziCore::ContainerRegistryRequestDecorator)
41
44
  end
42
45
  end
@@ -21,4 +21,12 @@ class UffizziCore::Api::Cli::V1::Projects::Deployments::ContainersController <
21
21
 
22
22
  respond_with containers
23
23
  end
24
+
25
+ def k8s_container_description
26
+ deployment ||= resource_project.deployments.existed.find(params[:deployment_id])
27
+ container = deployment.containers.active.find_by!(service_name: params[:container_name])
28
+ last_state = UffizziCore::ContainerService.last_state(container)
29
+
30
+ render json: { last_state: last_state }
31
+ end
24
32
  end
@@ -1,4 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class UffizziCore::ComposeFile::BuildError < StandardError
3
+ class UffizziCore::ComposeFile::BuildError < UffizziCore::ComposeFileError
4
+ def initialize(message, extra_errors = {})
5
+ error_key = UffizziCore::ComposeFile::ErrorsService::TEMPLATE_BUILD_ERROR_KEY
6
+
7
+ super(message, error_key, extra_errors)
8
+ end
4
9
  end
@@ -1,4 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class UffizziCore::ComposeFile::SecretsError < StandardError
3
+ class UffizziCore::ComposeFile::SecretsError < UffizziCore::ComposeFileError
4
+ def initialize(message, extra_errors = {})
5
+ error_key = UffizziCore::ComposeFile::ErrorsService::SECRETS_ERROR_KEY
6
+
7
+ super(message, error_key, extra_errors)
8
+ end
4
9
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFileError < StandardError
4
+ attr_reader :errors
5
+
6
+ def initialize(message, error_key = nil, extra_errors = {})
7
+ if [NilClass, String].exclude?(error_key.class)
8
+ raise StandardError.new("#{self.class} arg 'error_key' should be a #{String} or #{NilClass}")
9
+ end
10
+
11
+ unless extra_errors.is_a?(Hash)
12
+ raise StandardError.new("#{self.class} arg 'extra_errors' should be a #{Hash}")
13
+ end
14
+
15
+ @errors = error_key.nil? ? {} : { error_key => message.to_s }.merge(extra_errors)
16
+
17
+ super(message)
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ContainerRegistryError < StandardError
4
+ attr_reader :errors, :error_key
5
+
6
+ def initialize(response)
7
+ prepared_errors = prepare_errors(response[:body], response[:status])
8
+ @error_key = UffizziCore::ComposeFile::ErrorsService::DOCKER_REGISTRY_CONTAINER_ERROR_KEY
9
+ @errors = { @error_key => prepared_errors }
10
+
11
+ super(prepared_errors.to_json)
12
+ end
13
+
14
+ private
15
+
16
+ def prepare_errors(body, status)
17
+ parsed_body = JSON.parse!(body.to_s)
18
+
19
+ parsed_body.fetch('errors', parsed_body)
20
+ rescue JSON::ParserError, TypeError
21
+ msg = body.empty? ? I18n.t('registry.error', code: status) : body
22
+
23
+ { message: msg }
24
+ end
25
+ end
@@ -3,6 +3,8 @@
3
3
  class UffizziCore::Api::Cli::V1::ComposeFile::CheckCredentialsForm
4
4
  include UffizziCore::ApplicationFormWithoutActiveRecord
5
5
 
6
+ attr_reader :type
7
+
6
8
  attribute :compose_file
7
9
  attribute :credentials
8
10
 
@@ -16,13 +18,16 @@ class UffizziCore::Api::Cli::V1::ComposeFile::CheckCredentialsForm
16
18
  compose_data = UffizziCore::ComposeFileService.parse(compose_content, compose_payload)
17
19
 
18
20
  containers = compose_data[:containers]
19
- containers.map do |container|
21
+ containers.each do |container|
20
22
  container_registry_service = UffizziCore::ContainerRegistryService.init_by_container(container)
21
- credential = container_registry_service.credential(credentials)
22
- next credential if container_registry_service.image_available?(credentials)
23
+ @type = container_registry_service.type
24
+ next if container_registry_service.image_available?(credentials)
23
25
 
24
- raise UffizziCore::ComposeFile::CredentialError.new(I18n.t('compose.unprocessable_image', value: container_registry_service.type))
26
+ raise UffizziCore::ComposeFile::CredentialError.new(I18n.t('compose.unprocessable_image', value: type))
25
27
  end
28
+ rescue UffizziCore::ContainerRegistryError => e
29
+ errors.add(:credentials, I18n.t('compose.unprocessable_image', value: type))
30
+ errors.add(e.error_key, e.message)
26
31
  rescue UffizziCore::ComposeFile::CredentialError => e
27
32
  errors.add(:credentials, e.message)
28
33
  end
@@ -3,9 +3,6 @@
3
3
  class UffizziCore::Api::Cli::V1::ComposeFile::TemplateForm
4
4
  include UffizziCore::ApplicationFormWithoutActiveRecord
5
5
 
6
- SECRETS_ERROR_KEY = 'secret_variables'
7
- TEMPLATE_BUILD_ERROR_KEY = 'template_build_error'
8
-
9
6
  attribute :credentials
10
7
  attribute :project, UffizziCore::Project
11
8
  attribute :user, UffizziCore::User
@@ -34,13 +31,18 @@ class UffizziCore::Api::Cli::V1::ComposeFile::TemplateForm
34
31
  private
35
32
 
36
33
  def check_template_attributes
37
- case template_build_error
38
- when UffizziCore::ComposeFile::SecretsError
39
- errors.add(SECRETS_ERROR_KEY, template_build_error.message)
40
- when UffizziCore::ComposeFile::BuildError
41
- errors.add(TEMPLATE_BUILD_ERROR_KEY, template_build_error.message)
42
- when StandardError
43
- raise template_build_error
34
+ readable_errors = [
35
+ UffizziCore::ComposeFile::SecretsError,
36
+ UffizziCore::ComposeFile::BuildError,
37
+ UffizziCore::ContainerRegistryError,
38
+ ]
39
+
40
+ if readable_errors.include?(template_build_error.class)
41
+ template_build_error.errors.each { |k, v| errors.add(k, v) }
42
+
43
+ return
44
44
  end
45
+
46
+ raise template_build_error if template_build_error.is_a?(StandardError)
45
47
  end
46
48
  end
@@ -4,4 +4,8 @@ class UffizziCore::Api::Cli::V1::Projects::Deployments::ContainersPolicy < Uffiz
4
4
  def index?
5
5
  context.user_access_module.any_access_to_project?(context.user, context.project)
6
6
  end
7
+
8
+ def k8s_container_description?
9
+ context.user_access_module.any_access_to_project?(context.user, context.project)
10
+ end
7
11
  end
@@ -21,7 +21,8 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentSerializer::ContainerSerial
21
21
  :continuously_deploy,
22
22
  :receive_incoming_requests,
23
23
  :healthcheck,
24
- :volumes
24
+ :volumes,
25
+ :service_name
25
26
 
26
27
  def secret_variables
27
28
  return unless object.secret_variables.present?
@@ -79,7 +79,9 @@ class UffizziCore::ComposeFile::Builders::ContainerBuilderService
79
79
  return docker_repo_builder.build_attributes(image_data)
80
80
  end
81
81
 
82
- raise UffizziCore::ComposeFile::BuildError, I18n.t('compose.unprocessable_image', value: container_registry.type)
82
+ UffizziCore::ComposeFile::ErrorsService.raise_build_error!(container_registry.type)
83
+ rescue UffizziCore::ContainerRegistryError => e
84
+ UffizziCore::ComposeFile::ErrorsService.raise_build_error!(container_registry.type, e.errors)
83
85
  end
84
86
 
85
87
  def set_continuous_preview_attributes_to_repo(repo_attributes, global_data, container_data)
@@ -2,6 +2,9 @@
2
2
 
3
3
  class UffizziCore::ComposeFile::ErrorsService
4
4
  SECRETS_ERROR_KEY = 'secret_variables'
5
+ TEMPLATE_BUILD_ERROR_KEY = 'template_build_error'
6
+ DOCKER_REGISTRY_CONTAINER_ERROR_KEY = 'docker_registry_container_error'
7
+
5
8
  class << self
6
9
  def has_error?(compose_file, error_code)
7
10
  error = compose_file.payload.dig('errors', error_code)
@@ -42,5 +45,10 @@ class UffizziCore::ComposeFile::ErrorsService
42
45
 
43
46
  compose_file
44
47
  end
48
+
49
+ def raise_build_error!(type, extra_errors = {})
50
+ msg = I18n.t('compose.unprocessable_image', value: type)
51
+ raise UffizziCore::ComposeFile::BuildError.new(msg, extra_errors)
52
+ end
45
53
  end
46
54
  end
@@ -7,9 +7,7 @@ class UffizziCore::ContainerRegistry::AzureService
7
7
  end
8
8
 
9
9
  def credential_correct?(credential)
10
- client(credential).authentificated?
11
- rescue URI::InvalidURIError, Faraday::ConnectionFailed
12
- false
10
+ client(credential).authenticated?
13
11
  end
14
12
 
15
13
  private
@@ -14,9 +14,7 @@ class UffizziCore::ContainerRegistry::DockerHubService
14
14
  def image_available?(credential, image_data)
15
15
  namespace = image_data[:namespace]
16
16
  repo_name = image_data[:name]
17
- client = UffizziCore::DockerHubClient.new(credential)
18
- response = client.repository(namespace: namespace, image: repo_name)
19
- return false if not_found?(response)
17
+ client(credential).repository(namespace: namespace, image: repo_name)
20
18
 
21
19
  true
22
20
  end
@@ -24,9 +22,9 @@ class UffizziCore::ContainerRegistry::DockerHubService
24
22
  def user_client(credential)
25
23
  return @client if @client&.credential&.username == credential.username
26
24
 
27
- @client = UffizziCore::DockerHubClient.new(credential)
25
+ @client = client(credential)
28
26
 
29
- unless @client.authentificated?
27
+ unless @client.authenticated?
30
28
  Rails.logger.warn("broken credentials, DockerHubService credential_id=#{credential.id}")
31
29
  credential.unauthorize! unless credential.unauthorized?
32
30
  end
@@ -35,14 +33,14 @@ class UffizziCore::ContainerRegistry::DockerHubService
35
33
  end
36
34
 
37
35
  def digest(credential, image, tag)
38
- docker_hub_client = UffizziCore::DockerHubClient.new(credential)
36
+ docker_hub_client = client(credential)
39
37
  token = docker_hub_client.get_token(image).result.token
40
38
  response = docker_hub_client.digest(image: image, tag: tag, token: token)
41
39
  response.headers['docker-content-digest']
42
40
  end
43
41
 
44
42
  def credential_correct?(credential)
45
- client(credential).authentificated?
43
+ client(credential).authenticated?
46
44
  end
47
45
 
48
46
  private
@@ -50,9 +48,5 @@ class UffizziCore::ContainerRegistry::DockerHubService
50
48
  def client(credential)
51
49
  UffizziCore::DockerHubClient.new(credential)
52
50
  end
53
-
54
- def not_found?(response)
55
- response.status == 404
56
- end
57
51
  end
58
52
  end
@@ -5,9 +5,9 @@ class UffizziCore::ContainerRegistry::DockerRegistryService
5
5
  def image_available?(credential, image_data)
6
6
  client_params = build_client_params(credential, image_data)
7
7
  client = UffizziCore::DockerRegistryClient.new(**client_params)
8
- response = client.manifests(namespace: image_data[:namespace], image: image_data[:name], tag: image_data[:tag])
8
+ client.manifests(namespace: image_data[:namespace], image: image_data[:name], tag: image_data[:tag])
9
9
 
10
- response.status < 400
10
+ true
11
11
  end
12
12
 
13
13
  def credential_correct?(credential)
@@ -7,15 +7,7 @@ class UffizziCore::ContainerRegistry::GithubContainerRegistryService
7
7
  end
8
8
 
9
9
  def credential_correct?(credential)
10
- client(credential).authentificated?
11
- rescue URI::InvalidURIError, Faraday::ConnectionFailed
12
- false
13
- end
14
-
15
- def access_token(credential)
16
- client(credential).token
17
- rescue URI::InvalidURIError, Faraday::ConnectionFailed
18
- false
10
+ client(credential).authenticated?
19
11
  end
20
12
 
21
13
  private
@@ -13,9 +13,7 @@ class UffizziCore::ContainerRegistry::GoogleService
13
13
  end
14
14
 
15
15
  def credential_correct?(credential)
16
- client(credential).authentificated?
17
- rescue URI::InvalidURIError, Faraday::ConnectionFailed
18
- false
16
+ client(credential).authenticated?
19
17
  end
20
18
 
21
19
  private
@@ -62,6 +62,8 @@ class UffizziCore::ContainerRegistryService
62
62
 
63
63
  def credential_correct?(credential)
64
64
  service.credential_correct?(credential)
65
+ rescue URI::InvalidURIError, Faraday::ConnectionFailed, UffizziCore::ContainerRegistryError
66
+ false
65
67
  end
66
68
 
67
69
  def image_data
@@ -38,5 +38,33 @@ class UffizziCore::ContainerService
38
38
 
39
39
  container_memory_request <= max_memory_limit
40
40
  end
41
+
42
+ def last_state(container)
43
+ pods = pods_by_container(container)
44
+ container_status = container_status(container, pods)
45
+ return {} if container_status.blank? || container_status&.dig('last_state')&.blank?
46
+
47
+ container_status['last_state'].map do |code, state|
48
+ {
49
+ code: code,
50
+ reason: state.reason,
51
+ exit_code: state.exit_code,
52
+ started_at: state.started_at,
53
+ finished_at: state.finished_at,
54
+ }
55
+ end.first
56
+ end
57
+
58
+ private
59
+
60
+ def container_status(container, pods)
61
+ pods
62
+ .flat_map { |pod| pod&.status&.container_statuses }
63
+ .detect { |cs| cs.name.include?(container.controller_name) }
64
+ end
65
+
66
+ def pods_by_container(container)
67
+ UffizziCore::ControllerService.fetch_pods(container.deployment)
68
+ end
41
69
  end
42
70
  end
@@ -10,6 +10,7 @@ en:
10
10
  invalid_compose_message: |
11
11
  :exclamation: **Preview failed: invalid compose**
12
12
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Uffizzi was unable to deploy a preview of this pull request because the compose file in this branch is invalid.
13
+
13
14
  compose:
14
15
  unsupported_file: Unsupported compose file
15
16
  invalid_file: 'Syntax error: %{err} at line %{line} column %{column}'
@@ -70,14 +71,18 @@ en:
70
71
  required_start_commands: "When 'test' is a list the first item must be one of: '%{available_commands}'"
71
72
  volumes_should_be_array: Volumes '%{volumes}' should be an arra
72
73
  healthcheck_missing_required_option: "One of these options is required: %{required_options}"
74
+
73
75
  secrets:
74
76
  duplicates_exists: Secret with key %{secrets} already exist.
75
77
  invalid_key_length: A secret key must be no longer than 256 characters.
78
+
76
79
  deployment:
77
80
  invalid_state: Preview with ID deployment-%{id} %{state}
81
+
78
82
  session:
79
83
  unsupported_login_type: This type of login is not supported
80
84
  unauthorized: Unauthorized
85
+
81
86
  enumerize:
82
87
  credential:
83
88
  type:
@@ -87,3 +92,6 @@ en:
87
92
  "UffizziCore::Credential::Azure": "Azure"
88
93
  "UffizziCore::Credential::Google": "Google"
89
94
  "UffizziCore::Credential::Amazon": "Amazon"
95
+
96
+ registry:
97
+ error: Container registry returned a %{code} error
data/config/routes.rb CHANGED
@@ -16,6 +16,7 @@ UffizziCore::Engine.routes.draw do
16
16
  resources :activity_items, only: ['index']
17
17
  resources :events, only: ['index']
18
18
  resources :containers, only: ['index'], param: :name do
19
+ get :k8s_container_description
19
20
  scope module: :containers do
20
21
  resources :logs, only: ['index']
21
22
  resources :builds, only: [] do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UffizziCore
4
- VERSION = '2.0.19'
4
+ VERSION = '2.0.20'
5
5
  end
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.0.19
4
+ version: 2.0.20
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: 2022-12-29 00:00:00.000000000 Z
12
+ date: 2023-01-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aasm
@@ -732,6 +732,7 @@ files:
732
732
  - app/clients/uffizzi_core/amazon_registry_client.rb
733
733
  - app/clients/uffizzi_core/azure_registry_client.rb
734
734
  - app/clients/uffizzi_core/azure_registry_client/request_result.rb
735
+ - app/clients/uffizzi_core/container_registry_request_decorator.rb
735
736
  - app/clients/uffizzi_core/controller_client.rb
736
737
  - app/clients/uffizzi_core/controller_client/request_result.rb
737
738
  - app/clients/uffizzi_core/docker_hub_client.rb
@@ -774,6 +775,8 @@ files:
774
775
  - app/errors/uffizzi_core/compose_file/credential_error.rb
775
776
  - app/errors/uffizzi_core/compose_file/parse_error.rb
776
777
  - app/errors/uffizzi_core/compose_file/secrets_error.rb
778
+ - app/errors/uffizzi_core/compose_file_error.rb
779
+ - app/errors/uffizzi_core/container_registry_error.rb
777
780
  - app/errors/uffizzi_core/deployment/image_pull_error.rb
778
781
  - app/errors/uffizzi_core/deployment/labels_not_found_error.rb
779
782
  - app/errors/uffizzi_core/deployment_not_found_error.rb