Skip to content

Commit 04c2339

Browse files
authored
Merge pull request #2326 from lizardruss/local-repository
Local registry
2 parents 4d8586c + 724d8d4 commit 04c2339

638 files changed

Lines changed: 69576 additions & 18236 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/build.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import (
1010
// NewBuildCmd creates a new devspace build command
1111
func NewBuildCmd(f factory.Factory, globalFlags *flags.GlobalFlags, rawConfig *RawConfig) *cobra.Command {
1212
cmd := &RunPipelineCmd{
13-
GlobalFlags: globalFlags,
14-
Pipeline: "build",
15-
ForceBuild: true,
13+
GlobalFlags: globalFlags,
14+
Pipeline: "build",
15+
ForceBuild: true,
16+
SkipPushLocalKubernetes: true,
1617
}
1718

1819
var pipeline *latest.Pipeline

cmd/cleanup/cleanup.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func NewCleanupCmd(f factory.Factory, globalFlags *flags.GlobalFlags, plugins []
2121
}
2222

2323
cleanupCmd.AddCommand(newImagesCmd(f, globalFlags))
24+
cleanupCmd.AddCommand(newLocalRegistryCmd(f, globalFlags))
2425

2526
// Add plugin commands
2627
plugin.AddPluginCommands(cleanupCmd, plugins, "cleanup")

cmd/cleanup/local_registry.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package cleanup
2+
3+
import (
4+
"context"
5+
6+
"github.com/loft-sh/devspace/cmd/flags"
7+
"github.com/loft-sh/devspace/pkg/devspace/build/registry"
8+
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
9+
"github.com/loft-sh/devspace/pkg/util/factory"
10+
"github.com/loft-sh/devspace/pkg/util/message"
11+
"github.com/loft-sh/devspace/pkg/util/survey"
12+
"github.com/sirupsen/logrus"
13+
kerrors "k8s.io/apimachinery/pkg/api/errors"
14+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
16+
"github.com/pkg/errors"
17+
"github.com/spf13/cobra"
18+
)
19+
20+
type localRegistryCmd struct {
21+
*flags.GlobalFlags
22+
}
23+
24+
func newLocalRegistryCmd(f factory.Factory, globalFlags *flags.GlobalFlags) *cobra.Command {
25+
cmd := &localRegistryCmd{GlobalFlags: globalFlags}
26+
27+
localRegistryCmd := &cobra.Command{
28+
Use: "local-registry",
29+
Short: "Deletes the local image registry",
30+
Long: `
31+
#######################################################
32+
######### devspace cleanup local-registry #############
33+
#######################################################
34+
Deletes the local image registry
35+
#######################################################
36+
`,
37+
Args: cobra.NoArgs,
38+
RunE: func(cobraCmd *cobra.Command, args []string) error {
39+
return cmd.RunCleanupLocalRegistry(f, cobraCmd, args)
40+
}}
41+
42+
return localRegistryCmd
43+
}
44+
45+
// RunCleanupLocalRegistry executes the cleanup local-registry command logic
46+
func (cmd *localRegistryCmd) RunCleanupLocalRegistry(f factory.Factory, cobraCmd *cobra.Command, args []string) error {
47+
ctx := context.Background()
48+
log := f.GetLog()
49+
50+
// set config root
51+
configLoader, err := f.NewConfigLoader(cmd.ConfigPath)
52+
if err != nil {
53+
return err
54+
}
55+
configExists, err := configLoader.SetDevSpaceRoot(log)
56+
if err != nil {
57+
return err
58+
} else if !configExists {
59+
return errors.New(message.ConfigNotFound)
60+
}
61+
62+
// create kubectl client
63+
client, err := f.NewKubeClientFromContext(cmd.KubeContext, cmd.Namespace)
64+
if err != nil {
65+
log.Warnf("Unable to create new kubectl client: %v", err)
66+
log.WriteString(logrus.WarnLevel, "\n")
67+
client = nil
68+
}
69+
70+
// load generated config
71+
localCache, err := configLoader.LoadLocalCache()
72+
if err != nil {
73+
return errors.Errorf("error loading local cache: %v", err)
74+
}
75+
76+
if client != nil {
77+
// If the current kube context or namespace is different than old,
78+
// show warnings and reset kube client if necessary
79+
client, err = kubectl.CheckKubeContext(client, localCache, cmd.NoWarn, cmd.SwitchContext, false, log)
80+
if err != nil {
81+
return err
82+
}
83+
}
84+
85+
// load config
86+
configInterface, err := configLoader.LoadWithCache(ctx, localCache, client, cmd.ToConfigOptions(), log)
87+
if err != nil {
88+
return err
89+
}
90+
91+
// clean up registry according to options
92+
config := configInterface.Config()
93+
options := registry.NewDefaultOptions().
94+
WithNamespace(client.Namespace()).
95+
WithLocalRegistryConfig(config.LocalRegistry)
96+
97+
hasStatefulSet := true
98+
_, err = client.KubeClient().AppsV1().StatefulSets(options.Namespace).Get(ctx, options.Name, v1.GetOptions{})
99+
if err != nil {
100+
if kerrors.IsNotFound(err) {
101+
hasStatefulSet = false
102+
} else {
103+
return errors.Wrap(err, "clean up statefulset")
104+
}
105+
}
106+
107+
hasDeployment := true
108+
_, err = client.KubeClient().AppsV1().Deployments(options.Namespace).Get(ctx, options.Name, v1.GetOptions{})
109+
if err != nil {
110+
if kerrors.IsNotFound(err) {
111+
hasDeployment = false
112+
} else {
113+
return errors.Wrap(err, "clean up statefulset")
114+
}
115+
}
116+
117+
hasService := true
118+
_, err = client.KubeClient().CoreV1().Services(options.Namespace).Get(ctx, options.Name, v1.GetOptions{})
119+
if err != nil {
120+
if kerrors.IsNotFound(err) {
121+
hasService = false
122+
} else {
123+
return errors.Wrap(err, "clean up statefulset")
124+
}
125+
}
126+
127+
if !hasStatefulSet && !hasDeployment && !hasService {
128+
log.Donef("No local registry found.")
129+
return nil
130+
}
131+
132+
// prompt user since this is a destructive action
133+
cleanupAnswer, err := log.Question(&survey.QuestionOptions{
134+
Question: "This will delete your local registry and all the images it contains. Do you wish to continue?",
135+
Options: []string{
136+
"Yes",
137+
"No",
138+
},
139+
})
140+
if err != nil {
141+
return err
142+
}
143+
144+
if cleanupAnswer == "No" {
145+
return nil
146+
}
147+
148+
if hasStatefulSet {
149+
err = client.KubeClient().AppsV1().StatefulSets(options.Namespace).Delete(ctx, options.Name, v1.DeleteOptions{})
150+
if err != nil && !kerrors.IsNotFound(err) {
151+
return errors.Wrap(err, "clean up statefulset")
152+
}
153+
}
154+
155+
if hasDeployment {
156+
err = client.KubeClient().AppsV1().Deployments(options.Namespace).Delete(ctx, options.Name, v1.DeleteOptions{})
157+
if err != nil && !kerrors.IsNotFound(err) {
158+
return errors.Wrap(err, "clean up deployment")
159+
}
160+
}
161+
162+
if hasService {
163+
err = client.KubeClient().CoreV1().Services(options.Namespace).Delete(ctx, options.Name, v1.DeleteOptions{})
164+
if err != nil && !kerrors.IsNotFound(err) {
165+
return errors.Wrap(err, "clean up service")
166+
}
167+
}
168+
169+
log.Donef("Successfully cleaned up local registry")
170+
return nil
171+
}

cmd/init.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,19 @@ func annotateConfig(configPath string) error {
662662
# tag: v1.0.0
663663
# ui:
664664
# path: ./ui # Path-based dependencies (for monorepos)
665+
`)...)
666+
667+
annotatedConfig = append(annotatedConfig, []byte(`
668+
# Customize local registry settings
669+
# localRegistry:
670+
# enabled: true # Always use local registry, remove to only use the local registry when required
671+
# name: registry
672+
# namespace: ${devspace.namespace} # Uses the current kube context's namespace (can be removed)
673+
# image: registry:2.8.1
674+
# port: 5000
675+
# persistence:
676+
# enabled: false
677+
# size: 5Gi
665678
`)...)
666679

667680
err = ioutil.WriteFile(configPath, annotatedConfig, os.ModePerm)

e2e/e2e_suite_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
_ "github.com/loft-sh/devspace/e2e/tests/hooks"
1919
_ "github.com/loft-sh/devspace/e2e/tests/imports"
2020
_ "github.com/loft-sh/devspace/e2e/tests/init"
21+
_ "github.com/loft-sh/devspace/e2e/tests/localregistry"
2122
_ "github.com/loft-sh/devspace/e2e/tests/pipelines"
2223
_ "github.com/loft-sh/devspace/e2e/tests/portforward"
2324
_ "github.com/loft-sh/devspace/e2e/tests/proxycommands"

e2e/tests/config/config.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package config
33
import (
44
"bytes"
55
"fmt"
6-
"github.com/loft-sh/devspace/pkg/devspace/config/constants"
6+
"io/ioutil"
77
"os"
88
"path/filepath"
99

10+
"github.com/loft-sh/devspace/pkg/devspace/config/constants"
11+
1012
"github.com/loft-sh/devspace/pkg/devspace/config/loader"
1113
"github.com/loft-sh/devspace/pkg/devspace/config/loader/variable"
1214
"github.com/loft-sh/devspace/pkg/devspace/config/localcache"
@@ -106,8 +108,11 @@ var _ = DevSpaceDescribe("config", func() {
106108
// read the generated.yaml
107109
config, err := localcache.NewCacheLoader().Load(constants.DefaultConfigPath)
108110
framework.ExpectNoError(err)
111+
109112
ic, _ := config.GetImageCache("app-test")
110-
framework.ExpectLocalFileContentsImmediately(filepath.Join(tempDir, "out0.txt"), "my-docker-username/helloworld2:"+ic.Tag)
113+
out, err := ioutil.ReadFile(filepath.Join(tempDir, "out0.txt"))
114+
framework.ExpectNoError(err)
115+
gomega.Expect(string(out)).To(gomega.MatchRegexp("my-docker-username/helloworld2:" + ic.Tag))
111116
})
112117

113118
ginkgo.It("should load multiple profiles in order via --profile", func() {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package localregistry
2+
3+
import "github.com/onsi/ginkgo"
4+
5+
// DevSpaceDescribe annotates the test with the label.
6+
func DevSpaceDescribe(text string, body func()) bool {
7+
return ginkgo.Describe("[localregistry] "+text, body)
8+
}

0 commit comments

Comments
 (0)