8000 feat: unchecked registry use local images by robot9706 · Pull Request #745 · dyrector-io/dyrectorio · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: unchecked registry use local images #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions golang/internal/helper/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,15 @@ func pullImage(ctx context.Context, cli client.APIClient, imageName, encodedAuth

// CustomImagePull is a client side `smart` Pull, that only pulls if the digests are not matching
func CustomImagePull(ctx context.Context, cli client.APIClient,
imageName, encodedAuth string, forcePull, preferLocal bool, displayFn PullDisplayFn,
imageName, encodedAuth string, imagePriority PullPriority, displayFn PullDisplayFn,
) error {
distributionRef, err := parseDistributionRef(imageName)
if err != nil {
return err
}

if !forcePull {
useLocalImage, localImageErr := shouldUseLocalImage(ctx, cli, distributionRef, encodedAuth, preferLocal)
if imagePriority != ForcePull {
useLocalImage, localImageErr := shouldUseLocalImage(ctx, cli, distributionRef, encodedAuth, imagePriority == PreferLocal)
if localImageErr != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions golang/internal/helper/image/image_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func TestNewPull(t *testing.T) {
t.Fatal(err)
}
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout})
err = image.CustomImagePull(ctx, client, nginxImage, "", false, false, cli.DockerPullProgressDisplayer)
err = image.CustomImagePull(ctx, client, nginxImage, "", image.LocalOnly, cli.DockerPullProgressDisplayer)
assert.Nilf(t, err, "expected err to be nil for a valid image name")
}

Expand All @@ -90,7 +90,7 @@ func TestPullFullQualifiedImage(t *testing.T) {
return nil
})

err = image.CustomImagePull(ctx, cli, nginxImage, "", true, false, cb)
err = image.CustomImagePull(ctx, cli, nginxImage, "", image.ForcePull, cb)
assert.Nilf(t, err, "expected err to be nil for a valid image name")
assert.Truef(t, called, "display func is called")

Expand All @@ -108,7 +108,7 @@ func TestPrettyPullFullQualifiedInvalidImage(t *testing.T) {
img := fmt.Sprintf("%s:nonexistenttag", nginxImageNoTag)
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout})

err = image.CustomImagePull(ctx, client, img, "", false, false, cli.DockerPullProgressDisplayer)
err = image.CustomImagePull(ctx, client, img, "", image.LocalOnly, cli.DockerPullProgressDisplayer)
assert.ErrorIs(t, err, image.ErrImageNotFound, "expected err to be notfound for a invalid image name")
}

Expand Down
8 changes: 8 additions & 0 deletions golang/internal/helper/image/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import (
"io"
)

type PullPriority int32

const (
LocalOnly PullPriority = 0
PreferLocal PullPriority = 1
ForcePull PullPriority = 2
)

// RegistryAuth defines an image registry and the authentication information
// associated with it.
type RegistryAuth struct {
Expand Down
44 changes: 24 additions & 20 deletions golang/pkg/builder/container/container_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
type Builder interface {
WithClient(client client.APIClient) Builder
WithImage(imageWithTag string) Builder
WithLocalImagePriority() Builder
WithImagePriority(priority imageHelper.PullPriority) Builder
WithEnv(env []string) Builder
WithPortBindings(portList []PortBinding) Builder
WithPortRanges(portRanges []PortRangeBinding) Builder
Expand All @@ -50,7 +50,6 @@ type Builder interface {
WithUser(uid *int64) Builder
WithLogWriter(logger io.StringWriter) Builder
WithoutConflict() Builder
WithForcePullImage() Builder
WithPullDisplayFunc(imageHelper.PullDisplayFn) Builder
WithExtraHosts(hosts []string) Builder
WithPreCreateHooks(hooks ...LifecycleFunc) Builder
Expand All @@ -70,7 +69,6 @@ type DockerContainerBuilder struct {
networkAliases []string
containerName string
imageWithTag string
localImage bool
envList []string
labels map[string]string
logConfig *container.LogConfig
Expand All @@ -88,7 +86,7 @@ type DockerContainerBuilder struct {
shell []string
tty bool
user *int64
forcePull bool
imagePriority imageHelper.PullPriority
pullDisplayFn imageHelper.PullDisplayFn
logger io.StringWriter
extraHosts []string
Expand All @@ -104,8 +102,9 @@ type DockerContainerBuilder struct {
func NewDockerBuilder(ctx context.Context) Builder {
var logger io.StringWriter = defaultLogger{}
b := DockerContainerBuilder{
ctx: ctx,
logger: logger,
ctx: ctx,
logger: logger,
imagePriority: imageHelper.PreferLocal,
}

cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
Expand Down Expand Up @@ -175,8 +174,8 @@ func (dc *DockerContainerBuilder) WithImage(imageWithTag string) Builder {
}

// Sets the image of a container in a "image:tag" format where image can be a fully qualified name.
func (dc *DockerContainerBuilder) WithLocalImagePriority() Builder {
dc.localImage = true
func (dc *DockerContainerBuilder) WithImagePriority(priority imageHelper.PullPriority) Builder {
dc.imagePriority = priority
return dc
}

Expand Down Expand Up @@ -261,12 +260,6 @@ func (dc *DockerContainerBuilder) WithLogWriter(logger io.StringWriter) Builder
return dc
}

// Sets the builder to force pull the image before creating the container.
func (dc *DockerContainerBuilder) WithForcePullImage() Builder {
dc.forcePull = true
return dc
}

// Sets the builder to force pull the image before creating the container.
func (dc *DockerContainerBuilder) WithPullDisplayFunc(fn imageHelper.PullDisplayFn) Builder {
dc.pullDisplayFn = fn
Expand Down Expand Up @@ -385,11 +378,6 @@ func (dc *DockerContainerBuilder) Create() (Container, error) {
All: true,
Filters: filters.NewArgs(filters.KeyValuePair{Key: "id", Value: containerCreateResp.ID}),
})

if hookError := execHooks(dc, &containers[0], dc.hooksPostCreate); hookError != nil {
dc.logWrite(fmt.Sprintln("Container post-create hook error: ", err))
}

if err != nil {
dc.logWrite(fmt.Sprintf("Container list failed: %s", err.Error()))
}
Expand All @@ -399,6 +387,10 @@ func (dc *DockerContainerBuilder) Create() (Container, error) {
return nil, errors.New("container was not created")
}

if hookError := execHooks(dc, &containers[0], dc.hooksPostCreate); hookError != nil {
dc.logWrite(fmt.Sprintln("Container post-create hook error: ", err))
}

dc.containerID = &containers[0].ID
attachNetworks(dc)

Expand Down Expand Up @@ -447,7 +439,19 @@ func (dc *DockerContainerBuilder) prepareImage() error {
return err
}

err = imageHelper.CustomImagePull(dc.ctx, dc.client, expandedImageName, dc.registryAuth, dc.forcePull, dc.localImage, dc.pullDisplayFn)
if dc.imagePriority == imageHelper.LocalOnly {
dc.logWrite("Using local image only")
return nil
}

err = imageHelper.CustomImagePull(
dc.ctx,
dc.client,
expandedImageName,
dc.registryAuth,
dc.imagePriority,
dc.pullDisplayFn,
)
if err != nil && err.Error() != "EOF" {
return fmt.Errorf("image pull error: %s", err.Error())
}
Expand Down
3 changes: 2 additions & 1 deletion golang/pkg/cli/container_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/rs/zerolog/log"

v1 "github.com/dyrector-io/dyrectorio/golang/api/v1"
"github.com/dyrector-io/dyrectorio/golang/internal/helper/image"
"github.com/dyrector-io/dyrectorio/golang/internal/label"
containerbuilder "github.com/dyrector-io/dyrectorio/golang/pkg/builder/container"
dagentutils "github.com/dyrector-io/dyrectorio/golang/pkg/dagent/utils"
Expand Down Expand Up @@ -46,7 +47,7 @@ func baseContainer(ctx context.Context, args *ArgsFlags) containerbuilder.Builde
WithLogWriter(nil).
WithoutConflict()
if args.PreferLocalImages {
builder.WithLocalImagePriority()
builder.WithImagePriority(image.PreferLocal)
}
return builder
}
Expand Down
26 changes: 17 additions & 9 deletions golang/pkg/dagent/utils/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ func logDeployInfo(
log.Info().Str("requestID", reqID).Send()
}
dog.Write(
fmt.Sprintln("Starting container: ", containerName),
fmt.Sprintln("Using image: ", expandedImageName),
fmt.Sprintf("Starting container: %s", containerName),
fmt.Sprintf("Using image: %s", expandedImageName),
)

labels, _ := GetImageLabels(expandedImageName)
Expand Down Expand Up @@ -207,6 +207,15 @@ func writeDoggerError(dog *dogger.DeploymentLogger, msg string, err error) {
dog.WriteContainerState(common.ContainerState_CONTAINER_STATE_UNSPECIFIED, err.Error(), msg)
}

func getImageNameFromRequest(deployImageRequest *v1.DeployImageRequest) (string, error) {
imageName := util.JoinV(":", deployImageRequest.ImageName, deployImageRequest.Tag)
if deployImageRequest.Registry != nil && *deployImageRequest.Registry != "" {
imageName = util.JoinV("/", *deployImageRequest.Registry, imageName)
}

return imageHelper.ExpandImageName(imageName)
}

func DeployImage(ctx context.Context,
dog *dogger.DeploymentLogger,
deployImageRequest *v1.DeployImageRequest,
Expand All @@ -220,17 +229,12 @@ func DeployImage(ctx context.Context,
return err
}

imageName := util.JoinV("/",
*deployImageRequest.Registry,
util.JoinV(":", deployImageRequest.ImageName, deployImageRequest.Tag))

expandedImageName, err := imageHelper.ExpandImageName(imageName)
expandedImageName, err := getImageNameFromRequest(deployImageRequest)
if err != nil {
return fmt.Errorf("deployment failed, image name error: %w", err)
}

log.Debug().Str("name", imageName).Str("full", expandedImageName).Msg("Image name parsed")

log.Debug().Str("name", deployImageRequest.ImageName).Str("full", expandedImageName).Msg("Image name parsed")
logDeployInfo(dog, deployImageRequest, expandedImageName, containerName)

envMap := MergeStringMapUnique(deployImageRequest.InstanceConfig.Environment, deployImageRequest.ContainerConfig.Environment)
Expand Down Expand Up @@ -286,6 +290,10 @@ func DeployImage(ctx context.Context,
WithLogWriter(dog).
WithPullDisplayFunc(dog.WriteDockerPull)

if deployImageRequest.Registry == nil || *deployImageRequest.Registry == "" {
builder.WithImagePriority(imageHelper.LocalOnly)
}

WithInitContainers(builder, &deployImageRequest.ContainerConfig, dog, envMap, cfg)

cont, err := builder.CreateAndStart()
Expand Down
1 change: 1 addition & 0 deletions web/crux-ui/locales/en/registries.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"namespaceType": "Namespace type",
"project": "Project ID",
"userName": "User name",
"useLocalImages": "Use local images",

"tips": {
"common": "Registries contain the images you can select to use in your Projects and Versions.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DyoInput } from '@app/elements/dyo-input'
import { DyoLabel } from '@app/elements/dyo-label'
import DyoSwitch from '@app/elements/dyo-switch'
import { UncheckedRegistryDetails } from '@app/models'
import { EditRegistryTypeProps } from '@app/utils'
import useTranslation from 'next-translate/useTranslation'
Expand All @@ -13,16 +14,33 @@ const UncheckedRegistryFields = (props: EditRegistryTypeProps<UncheckedRegistryD
<>
<DyoLabel className="text-light mt-2">{t('tips.unchecked')}</DyoLabel>

<DyoInput
className="max-w-lg"
grow
name="url"
type="text"
label={t('url')}
>
value={formik.values.url}
message={formik.errors.url}
/>
<div className="flex mt-8">
<DyoLabel className="mr-2">{t('useLocalImages')}</DyoLabel>

<DyoSwitch
fieldName="local"
checked={formik.values.local ?? false}
setFieldValue={(field: string, value: boolean, shouldValidate?: boolean | undefined) => {
if (!value) {
formik.setFieldValue('url', '', false)
}
return formik.setFieldValue(field, value, shouldValidate)
}}
/>
</div>

{!formik.values.local && (
<DyoInput
className="max-w-lg"
grow
name="url"
type="text"
label={t('url')}
>
value={formik.values.url}
message={formik.errors.url}
/>
)}
</>
)
}
Expand Down
2 changes: 2 additions & 0 deletions web/crux-ui/src/models/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export type GoogleRegistryDetails = RegistryDetailsBase & GoogleRegistryDetailsD

type UncheckedRegistryDetailsDto = {
type: 'unchecked'
local?: boolean
url: string
}
export type UncheckedRegistryDetails = RegistryDetailsBase & UncheckedRegistryDetailsDto
Expand Down Expand Up @@ -272,6 +273,7 @@ export const registryDetailsDtoToUI = (dto: RegistryDetailsDto): RegistryDetails
return {
...registry,
...uncheckedDetails,
local: uncheckedDetails.url === '',
}
}

Expand Down
6 changes: 3 additions & 3 deletions web/crux-ui/src/validations/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ export const registrySchema = yup.object().shape({
url: yup
.string()
.meta(shouldResetMetaData)
.when(['type', 'selfManaged'], {
is: (type, selfManaged) =>
type === 'v2' || type === 'google' || (type === 'gitlab' && selfManaged) || type === 'unchecked',
.when(['type', 'selfManaged', 'local'], {
is: (type, selfManaged, local) =>
type === 'v2' || type === 'google' || (type === 'gitlab' && selfManaged) || (type === 'unchecked' && !local),
then: yup.string().required(),
})
.when(['type'], { is: type => type === 'google', then: yup.string().oneOf([...googleRegistryUrls]) }),
Expand Down
0