uffizzi_core 1.0.0 → 1.0.2
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.
- checksums.yaml +4 -4
- data/app/clients/uffizzi_core/docker_hub_client.rb +9 -0
- data/app/forms/uffizzi_core/api/cli/v1/deployment/create_form.rb +1 -1
- data/app/forms/uffizzi_core/api/cli/v1/deployment/update_form.rb +1 -0
- data/app/forms/uffizzi_core/api/cli/v1/template/create_form.rb +1 -1
- data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer.rb +2 -2
- data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +4 -2
- data/app/services/uffizzi_core/compose_file/container_service.rb +16 -7
- data/app/services/uffizzi_core/compose_file/parsers/services/healthcheck_parser_service.rb +23 -7
- data/app/services/uffizzi_core/docker_hub_service.rb +14 -0
- data/config/locales/en.yml +4 -3
- data/lib/uffizzi_core/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 520b79e2bc010eab840b4a6c4d31fe236c7b1e1a04714a42319399d904208b09
|
4
|
+
data.tar.gz: 4cdf4a4e66308a13bcb9740ea3aafb63d1de49c128fef7fb4d59731045ac1877
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e44e43bb064368f55ca82ad30eb989ee8503a65a2daad496f50608d983c39da93543ec8ea6cddeef7cbcf1367bd1916bc929fc7015b5fd0121d6eb987333f2e
|
7
|
+
data.tar.gz: 414e34bec819810a75c0fe13ca4652ab0a26d271f1bedd8d11d9e50f9ebbd918f83209205c5a0a5005f8db2c59889114268a961b8a4a93ea270c43e37b43f498
|
@@ -23,6 +23,15 @@ class UffizziCore::DockerHubClient
|
|
23
23
|
nil
|
24
24
|
end
|
25
25
|
|
26
|
+
def repository(namespace:, image:)
|
27
|
+
url = "#{BASE_URL}/v2/repositories/#{namespace}/#{image}"
|
28
|
+
|
29
|
+
response = connection.get(url) do |request|
|
30
|
+
request.headers['Authorization'] = "JWT #{jwt}"
|
31
|
+
end
|
32
|
+
RequestResult.new(status: response.status, result: response.body)
|
33
|
+
end
|
34
|
+
|
26
35
|
def public_images(q:, page: 1, per_page: 25)
|
27
36
|
url = "#{BASE_URL}/api/content/v1/products/search"
|
28
37
|
params = { page_size: per_page, q: q, type: :image, page: page }
|
@@ -17,10 +17,10 @@ class UffizziCore::Api::Cli::V1::Deployment::CreateForm < UffizziCore::Deploymen
|
|
17
17
|
:command,
|
18
18
|
:receive_incoming_requests,
|
19
19
|
:continuously_deploy,
|
20
|
-
{ healthcheck: {} },
|
21
20
|
{ variables: [:name, :value],
|
22
21
|
secret_variables: [:name, :value],
|
23
22
|
volumes: [:source, :target, :type, :read_only],
|
23
|
+
healthcheck: [:test, :interval, :timeout, :retries, :start_period, :disable, { test: [] }],
|
24
24
|
repo_attributes: [
|
25
25
|
:namespace,
|
26
26
|
:name,
|
@@ -19,6 +19,7 @@ class UffizziCore::Api::Cli::V1::Deployment::UpdateForm < UffizziCore::Deploymen
|
|
19
19
|
{ variables: [:name, :value],
|
20
20
|
secret_variables: [:name, :value],
|
21
21
|
volumes: [:source, :target, :type, :read_only],
|
22
|
+
healthcheck: [:test, :interval, :timeout, :retries, :start_period, :disable, { test: [] }],
|
22
23
|
repo_attributes: [
|
23
24
|
:namespace,
|
24
25
|
:name,
|
@@ -18,10 +18,10 @@ class UffizziCore::Api::Cli::V1::Template::CreateForm < UffizziCore::Template
|
|
18
18
|
:continuously_deploy,
|
19
19
|
:service_name,
|
20
20
|
:name,
|
21
|
-
:healthcheck,
|
22
21
|
{ variables: [:name, :value],
|
23
22
|
secret_variables: [:name, :value],
|
24
23
|
volumes: [:source, :target, :type, :read_only],
|
24
|
+
healthcheck: [:test, :interval, :timeout, :retries, :start_period, :disable, { test: [] }],
|
25
25
|
repo_attributes: [
|
26
26
|
:namespace,
|
27
27
|
:name,
|
@@ -53,7 +53,7 @@ class UffizziCore::Controller::DeployContainers::ContainerSerializer < UffizziCo
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def healthcheck
|
56
|
-
return {} if object.healthcheck.
|
56
|
+
return {} if object.healthcheck.blank?
|
57
57
|
|
58
58
|
command = object.healthcheck['test']
|
59
59
|
new_command = if command.is_a?(Array)
|
@@ -63,6 +63,6 @@ class UffizziCore::Controller::DeployContainers::ContainerSerializer < UffizziCo
|
|
63
63
|
command.split
|
64
64
|
end
|
65
65
|
|
66
|
-
object.healthcheck.merge(test
|
66
|
+
object.healthcheck.merge('test' => new_command)
|
67
67
|
end
|
68
68
|
end
|
@@ -206,9 +206,11 @@ class UffizziCore::ComposeFile::Builders::ContainerBuilderService
|
|
206
206
|
|
207
207
|
def build_docker_repo_attributes(image_data, credentials, scope, repo_type)
|
208
208
|
credential = credentials.send(scope).first
|
209
|
-
|
209
|
+
if UffizziCore::ComposeFile::ContainerService.image_available?(credential, image_data, scope)
|
210
|
+
return docker_builder(repo_type).build_attributes(image_data)
|
211
|
+
end
|
210
212
|
|
211
|
-
|
213
|
+
raise UffizziCore::ComposeFile::BuildError, I18n.t('compose.unprocessable_image', value: scope)
|
212
214
|
end
|
213
215
|
|
214
216
|
def variables(variables_data, dependencies)
|
@@ -55,23 +55,32 @@ class UffizziCore::ComposeFile::ContainerService
|
|
55
55
|
|
56
56
|
def credential_for_container(container, credentials)
|
57
57
|
if UffizziCore::ComposeFile::ContainerService.azure?(container)
|
58
|
-
detect_credential(credentials, :azure)
|
58
|
+
detect_credential(container, credentials, :azure)
|
59
59
|
elsif UffizziCore::ComposeFile::ContainerService.docker_hub?(container)
|
60
|
-
detect_credential(credentials, :docker_hub)
|
60
|
+
detect_credential(container, credentials, :docker_hub)
|
61
61
|
elsif UffizziCore::ComposeFile::ContainerService.google?(container)
|
62
|
-
detect_credential(
|
62
|
+
detect_credential(container, ecredentials, :google)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
def detect_credential(credentials, type)
|
66
|
+
def detect_credential(container, credentials, type)
|
67
67
|
credential = credentials.detect do |item|
|
68
68
|
item.send("#{type}?")
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
raise UffizziCore::ComposeFile::CredentialError.new(error_message) if credential.nil?
|
71
|
+
return credential if image_available?(credential, container[:image], type)
|
73
72
|
|
74
|
-
|
73
|
+
raise UffizziCore::ComposeFile::CredentialError.new(I18n.t('compose.unprocessable_image', value: type))
|
74
|
+
end
|
75
|
+
|
76
|
+
def image_available?(credential, image_data, type)
|
77
|
+
case type
|
78
|
+
when :docker_hub
|
79
|
+
UffizziCore::DockerHubService.image_available?(credential, image_data)
|
80
|
+
else
|
81
|
+
# TODO check image availability in other registry types
|
82
|
+
credential.present?
|
83
|
+
end
|
75
84
|
end
|
76
85
|
end
|
77
86
|
end
|
@@ -11,10 +11,10 @@ class UffizziCore::ComposeFile::Parsers::Services::HealthcheckParserService
|
|
11
11
|
|
12
12
|
{
|
13
13
|
test: command,
|
14
|
-
interval: parse_time(healthcheck_data['interval']),
|
15
|
-
timeout: parse_time(healthcheck_data['timeout']),
|
14
|
+
interval: parse_time(:interval, healthcheck_data['interval']),
|
15
|
+
timeout: parse_time(:timeout, healthcheck_data['timeout']),
|
16
16
|
retries: parse_retries(healthcheck_data['retries']),
|
17
|
-
start_period: parse_time(healthcheck_data['start_period']),
|
17
|
+
start_period: parse_time(:start_period, healthcheck_data['start_period']),
|
18
18
|
disable: parse_disable_option(healthcheck_data['disable'], command),
|
19
19
|
}
|
20
20
|
end
|
@@ -28,7 +28,11 @@ class UffizziCore::ComposeFile::Parsers::Services::HealthcheckParserService
|
|
28
28
|
case command
|
29
29
|
when Array
|
30
30
|
start_command = command.first
|
31
|
-
|
31
|
+
|
32
|
+
unless REQUIRED_START_COMMANDS.include?(start_command)
|
33
|
+
raise UffizziCore::ComposeFile::ParseError,
|
34
|
+
I18n.t('compose.required_start_commands', available_commands: REQUIRED_START_COMMANDS.join(', '))
|
35
|
+
end
|
32
36
|
|
33
37
|
command
|
34
38
|
when String
|
@@ -39,10 +43,22 @@ class UffizziCore::ComposeFile::Parsers::Services::HealthcheckParserService
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def parse_retries(value)
|
42
|
-
|
46
|
+
return if value.nil?
|
47
|
+
|
48
|
+
unless value.is_a?(Integer)
|
49
|
+
raise UffizziCore::ComposeFile::ParseError,
|
50
|
+
I18n.t('compose.invalid_retries', value: value)
|
51
|
+
end
|
52
|
+
|
53
|
+
value
|
43
54
|
end
|
44
55
|
|
45
|
-
def parse_time(value)
|
56
|
+
def parse_time(key, value)
|
57
|
+
return if value.nil?
|
58
|
+
|
59
|
+
error_message = I18n.t('compose.invalid_time_interval', key: key, value: value)
|
60
|
+
raise UffizziCore::ComposeFile::ParseError, error_message if value.is_a?(Integer)
|
61
|
+
|
46
62
|
tokens = {
|
47
63
|
's' => 1,
|
48
64
|
'm' => 60,
|
@@ -58,7 +74,7 @@ class UffizziCore::ComposeFile::Parsers::Services::HealthcheckParserService
|
|
58
74
|
|
59
75
|
acc
|
60
76
|
rescue StandardError
|
61
|
-
raise UffizziCore::ComposeFile::ParseError,
|
77
|
+
raise UffizziCore::ComposeFile::ParseError, error_message
|
62
78
|
end
|
63
79
|
end
|
64
80
|
|
@@ -11,6 +11,16 @@ class UffizziCore::DockerHubService
|
|
11
11
|
accounts_response.nil? ? [] : accounts_response.namespaces
|
12
12
|
end
|
13
13
|
|
14
|
+
def image_available?(credential, image_data)
|
15
|
+
namespace = image_data[:namespace]
|
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)
|
20
|
+
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
14
24
|
def user_client(credential)
|
15
25
|
return @client if @client&.credential&.username == credential.username
|
16
26
|
|
@@ -36,5 +46,9 @@ class UffizziCore::DockerHubService
|
|
36
46
|
def public_docker_hub_client
|
37
47
|
@public_docker_hub_client ||= UffizziCore::DockerHubClient.new
|
38
48
|
end
|
49
|
+
|
50
|
+
def not_found?(response)
|
51
|
+
response.status == 404
|
52
|
+
end
|
39
53
|
end
|
40
54
|
end
|
data/config/locales/en.yml
CHANGED
@@ -17,7 +17,7 @@ en:
|
|
17
17
|
no_services: Service services has neither an image nor a build context specified. At least one must be provided.
|
18
18
|
no_ingress: Service ingress has not been defined.
|
19
19
|
invalid_image_value: Invalid image value '%{value}'
|
20
|
-
|
20
|
+
unprocessable_image: Invalid credential '%{value} or image does not exist'
|
21
21
|
invalid_repo_type: Unsupported repo type
|
22
22
|
repo_not_found: The specified repository doesn't exist '%{name}'
|
23
23
|
ingress_port_not_specified: Ingress port not specified
|
@@ -56,8 +56,8 @@ en:
|
|
56
56
|
project_secret_not_found: Project secret '%{secret}' not found
|
57
57
|
continuous_preview_in_service_level: The option '%{option}' is not supported for service-level. Use 'x-uffizzi-continuous-preview' instead
|
58
58
|
file_already_exists: A compose file already exists for this project. Run 'uffizzi compose update' to update this file or 'uffizzi compose rm' to remove it. For more options, see 'uffizzi compose --help'
|
59
|
-
|
60
|
-
|
59
|
+
invalid_time_interval: "Invalid time interval: '%{key}:%{value}'. The time interval should be in the following format '{hours}h{minutes}m{seconds}s'. At least one value must be present."
|
60
|
+
invalid_retries: "Invalid retries value: 'retries:%{value}'. The value should be an integer."
|
61
61
|
string_or_array_error: "'%{option}' contains an invalid type, it should be a string, or an array"
|
62
62
|
not_implemented: "'%{option}' option is not implemented"
|
63
63
|
infinite_recursion: "Found infinite recursion for key '%{key}'"
|
@@ -67,6 +67,7 @@ en:
|
|
67
67
|
volume_type_not_supported: Volumes with type '%{type}' does not supported
|
68
68
|
named_volume_not_exists: Named volume '%{source_path}:%{target_path}' is used in service '%{service_name}' but no declaration was found in the volumes section.
|
69
69
|
invalid_volume_destination: Invalid volume specification '%{spec}' destination can't be '/'
|
70
|
+
required_start_commands: "When 'test' is a list the first item must be one of: '%{available_commands}'"
|
70
71
|
secrets:
|
71
72
|
duplicates_exists: Secret with key %{secrets} already exist.
|
72
73
|
invalid_key_length: A secret key must be no longer than 256 characters.
|
data/lib/uffizzi_core/version.rb
CHANGED
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: 1.0.
|
4
|
+
version: 1.0.2
|
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
|
+
date: 2022-09-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aasm
|