Skip to content

Commit 6e7d030

Browse files
committed
add connect, create & use commands
1 parent 02ad8fd commit 6e7d030

Some content is hidden

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

45 files changed

+7285
-8
lines changed

cmd/connect/cluster.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package connect
2+
3+
import (
4+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/cloud"
5+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/factory"
6+
7+
"github.com/mgutz/ansi"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
type clusterCmd struct {
12+
Provider string
13+
14+
UseHostNetwork bool
15+
Options *cloud.ConnectClusterOptions
16+
}
17+
18+
func newClusterCmd(f factory.Factory) *cobra.Command {
19+
cmd := &clusterCmd{
20+
Options: &cloud.ConnectClusterOptions{},
21+
}
22+
23+
clusterCmd := &cobra.Command{
24+
Use: "cluster",
25+
Short: "Connects an existing cluster to DevSpace Cloud",
26+
Long: `
27+
#######################################################
28+
############ devspace connect cluster #################
29+
#######################################################
30+
Connects an existing cluster to DevSpace Cloud.
31+
32+
Examples:
33+
devspace connect cluster
34+
#######################################################
35+
`,
36+
Args: cobra.NoArgs,
37+
RunE: func(cobraCmd *cobra.Command, args []string) error {
38+
return cmd.RunConnectCluster(f, cobraCmd, args)
39+
}}
40+
41+
clusterCmd.Flags().StringVar(&cmd.Provider, "provider", "", "The cloud provider to use")
42+
43+
clusterCmd.Flags().BoolVar(&cmd.Options.DeployAdmissionController, "admission-controller", true, "Deploy the admission controller")
44+
clusterCmd.Flags().BoolVar(&cmd.Options.DeployGatekeeper, "gatekeeper", false, "Deploy the gatekeeper")
45+
clusterCmd.Flags().BoolVar(&cmd.Options.DeployGatekeeperRules, "gatekeeper-rules", false, "Deploy the gatekeeper default rules")
46+
clusterCmd.Flags().BoolVar(&cmd.Options.DeployIngressController, "ingress-controller", true, "Deploy an ingress controller")
47+
clusterCmd.Flags().BoolVar(&cmd.UseHostNetwork, "use-hostnetwork", false, "Use the host network for the ingress controller instead of a loadbalancer")
48+
clusterCmd.Flags().BoolVar(&cmd.Options.DeployCertManager, "cert-manager", true, "Deploy a cert manager")
49+
clusterCmd.Flags().BoolVar(&cmd.Options.Public, "public", false, "Connects a new public cluster")
50+
clusterCmd.Flags().StringVar(&cmd.Options.KubeContext, "context", "", "The kube context to use")
51+
clusterCmd.Flags().StringVar(&cmd.Options.Key, "key", "", "The encryption key to use")
52+
clusterCmd.Flags().StringVar(&cmd.Options.ClusterName, "name", "", "The cluster name to create")
53+
54+
clusterCmd.Flags().BoolVar(&cmd.Options.OpenUI, "open-ui", false, "Opens the UI and displays the cluster overview")
55+
clusterCmd.Flags().BoolVar(&cmd.Options.UseDomain, "use-domain", false, "Use an automatic domain for the cluster")
56+
clusterCmd.Flags().StringVar(&cmd.Options.Domain, "domain", "", "The domain to use")
57+
58+
return clusterCmd
59+
}
60+
61+
// RunConnectCluster executes the connect cluster command logic
62+
func (cmd *clusterCmd) RunConnectCluster(f factory.Factory, cobraCmd *cobra.Command, args []string) error {
63+
log := f.GetLog()
64+
// Get provider
65+
provider, err := f.GetProvider(cmd.Provider, log)
66+
if err != nil {
67+
return err
68+
}
69+
70+
// Check if use host network was used
71+
if cobraCmd.Flags().Changed("use-hostnetwork") {
72+
cmd.Options.UseHostNetwork = &cmd.UseHostNetwork
73+
}
74+
75+
// Connect cluster
76+
err = provider.ConnectCluster(cmd.Options)
77+
if err != nil {
78+
return err
79+
}
80+
81+
log.Donef("Successfully connected cluster to DevSpace Cloud. \n\nYou can now run:\n- `%s` to create a new space\n- `%s` to list all connected clusters", ansi.Color("devspace create space [NAME]", "white+b"), ansi.Color("devspace list clusters", "white+b"))
82+
return nil
83+
}

cmd/connect/connect.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package connect
2+
3+
import (
4+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/factory"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
// NewConnectCmd creates a new cobra command
10+
func NewConnectCmd(f factory.Factory) *cobra.Command {
11+
connectCmd := &cobra.Command{
12+
Use: "connect",
13+
Short: "Connect an external cluster to devspace cloud",
14+
Long: `
15+
#######################################################
16+
################# devspace connect ####################
17+
#######################################################
18+
`,
19+
Args: cobra.NoArgs,
20+
}
21+
22+
connectCmd.AddCommand(newClusterCmd(f))
23+
24+
return connectCmd
25+
}

cmd/create/create.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package create
2+
3+
import (
4+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/factory"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
// NewCreateCmd creates a new cobra command
9+
func NewCreateCmd(f factory.Factory) *cobra.Command {
10+
createCmd := &cobra.Command{
11+
Use: "create",
12+
Short: "Create spaces in the cloud",
13+
Long: `
14+
#######################################################
15+
################## devspace create ####################
16+
#######################################################
17+
`,
18+
Args: cobra.NoArgs,
19+
}
20+
21+
createCmd.AddCommand(newSpaceCmd(f))
22+
23+
return createCmd
24+
}

cmd/create/space.go

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
package create
2+
3+
import (
4+
"github.com/devspace-cloud/devspace-cloud-plugin/cmd/use"
5+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/cloud"
6+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/cloud/config/versions/latest"
7+
"github.com/devspace-cloud/devspace-cloud-plugin/pkg/factory"
8+
9+
"github.com/devspace-cloud/devspace/pkg/devspace/config/loader"
10+
"github.com/devspace-cloud/devspace/pkg/util/log"
11+
"github.com/devspace-cloud/devspace/pkg/util/survey"
12+
"sort"
13+
14+
"github.com/mgutz/ansi"
15+
"github.com/pkg/errors"
16+
"github.com/spf13/cobra"
17+
)
18+
19+
// DevSpaceCloudHostedCluster is the option that is shown during cluster select to select the hosted devspace cloud clusters
20+
const DevSpaceCloudHostedCluster = "Clusters managed by DevSpace"
21+
22+
type SpaceCmd struct {
23+
Active bool
24+
Provider string
25+
Cluster string
26+
}
27+
28+
func newSpaceCmd(f factory.Factory) *cobra.Command {
29+
cmd := &SpaceCmd{}
30+
31+
SpaceCmd := &cobra.Command{
32+
Use: "space",
33+
Short: "Create a new cloud space",
34+
Long: `
35+
#######################################################
36+
############### devspace create space #################
37+
#######################################################
38+
Creates a new space
39+
40+
Example:
41+
devspace create space myspace
42+
#######################################################
43+
`,
44+
Args: cobra.ExactArgs(1),
45+
RunE: func(cobraCmd *cobra.Command, args []string) error {
46+
return cmd.RunCreateSpace(f, cobraCmd, args)
47+
},
48+
}
49+
50+
SpaceCmd.Flags().BoolVar(&cmd.Active, "active", true, "Use the new Space as active Space for the current project")
51+
SpaceCmd.Flags().StringVar(&cmd.Provider, "provider", "", "The cloud provider to use")
52+
SpaceCmd.Flags().StringVar(&cmd.Cluster, "cluster", "", "The cluster to create a space in")
53+
54+
return SpaceCmd
55+
}
56+
57+
// RunCreateSpace executes the "devspace create space" command logic
58+
func (cmd *SpaceCmd) RunCreateSpace(f factory.Factory, cobraCmd *cobra.Command, args []string) error {
59+
// Set config root
60+
logger := f.GetLog()
61+
configLoader := loader.NewConfigLoader(nil, logger)
62+
configExists, err := configLoader.SetDevSpaceRoot()
63+
if err != nil {
64+
return err
65+
}
66+
67+
// Get provider
68+
provider, err := f.GetProvider(cmd.Provider, logger)
69+
if err != nil {
70+
return err
71+
}
72+
73+
logger.StartWait("Retrieving clusters")
74+
defer logger.StopWait()
75+
76+
// Get projects
77+
projects, err := provider.Client().GetProjects()
78+
if err != nil {
79+
return errors.Wrap(err, "get projects")
80+
}
81+
82+
// Create project if needed
83+
projectID := 0
84+
if len(projects) == 0 {
85+
projectID, err = createProject(provider)
86+
if err != nil {
87+
return err
88+
}
89+
} else {
90+
projectID = projects[0].ProjectID
91+
}
92+
93+
var cluster *latest.Cluster
94+
if cmd.Cluster == "" {
95+
cluster, err = getCluster(provider, logger)
96+
if err != nil {
97+
return err
98+
}
99+
} else {
100+
cluster, err = provider.Client().GetClusterByName(cmd.Cluster)
101+
if err != nil {
102+
return err
103+
}
104+
}
105+
106+
logger.StartWait("Creating space " + args[0])
107+
defer logger.StopWait()
108+
109+
key, err := provider.GetClusterKey(cluster)
110+
if err != nil {
111+
return errors.Wrap(err, "get cluster key")
112+
}
113+
114+
// Create space
115+
spaceID, err := provider.Client().CreateSpace(args[0], key, projectID, cluster)
116+
if err != nil {
117+
return errors.Wrap(err, "create space")
118+
}
119+
120+
// Get Space
121+
space, err := provider.Client().GetSpace(spaceID)
122+
if err != nil {
123+
return errors.Wrap(err, "get space")
124+
}
125+
126+
// Get service account
127+
serviceAccount, err := provider.Client().GetServiceAccount(space, key)
128+
if err != nil {
129+
return errors.Wrap(err, "get serviceaccount")
130+
}
131+
132+
// Change kube context
133+
kubeContext := cloud.GetKubeContextNameFromSpace(space.Name, space.ProviderName)
134+
err = provider.UpdateKubeConfig(kubeContext, serviceAccount, spaceID, true)
135+
if err != nil {
136+
return errors.Wrap(err, "update kube context")
137+
}
138+
139+
// Cache space
140+
err = provider.CacheSpace(space, serviceAccount)
141+
if err != nil {
142+
return err
143+
}
144+
145+
logger.StopWait()
146+
logger.Infof("Successfully created space %s", space.Name)
147+
logger.Infof("Your kubectl context has been updated automatically.")
148+
149+
if configExists {
150+
logger.Infof("\r \nYou can now run: \n- `%s` to deploy the app to the cloud\n- `%s` to develop the app in the cloud\n", ansi.Color("devspace deploy", "white+b"), ansi.Color("devspace dev", "white+b"))
151+
}
152+
153+
// clear project kube context
154+
err = use.ClearProjectKubeContext(configLoader)
155+
if err != nil {
156+
return errors.Wrap(err, "clear generated kube context")
157+
}
158+
159+
return nil
160+
}
161+
162+
func getCluster(p cloud.Provider, logger log.Logger) (*latest.Cluster, error) {
163+
clusters, err := p.Client().GetClusters()
164+
if err != nil {
165+
return nil, errors.Wrap(err, "get clusters")
166+
}
167+
if len(clusters) == 0 {
168+
return nil, errors.New("Cannot create space, because no cluster was found")
169+
}
170+
171+
logger.StopWait()
172+
173+
// Check if the user has access to a connected cluster
174+
connectedClusters := make([]*latest.Cluster, 0, len(clusters))
175+
for _, cluster := range clusters {
176+
if cluster.Owner != nil {
177+
connectedClusters = append(connectedClusters, cluster)
178+
}
179+
}
180+
181+
// Check if user has connected clusters
182+
if len(connectedClusters) > 0 {
183+
clusterNames := []string{}
184+
for _, cluster := range connectedClusters {
185+
clusterNames = append(clusterNames, cluster.Name)
186+
}
187+
188+
sort.Strings(clusterNames)
189+
190+
// Check if there are non connected clusters
191+
for _, cluster := range clusters {
192+
if cluster.Owner == nil {
193+
// Add devspace cloud option
194+
clusterNames = append(clusterNames, DevSpaceCloudHostedCluster)
195+
break
196+
}
197+
}
198+
if len(clusterNames) == 1 {
199+
return connectedClusters[0], nil
200+
}
201+
202+
// Choose cluster
203+
chosenCluster, err := logger.Question(&survey.QuestionOptions{
204+
Question: "Which cluster should the space created in?",
205+
DefaultValue: clusterNames[0],
206+
Options: clusterNames,
207+
})
208+
if err != nil {
209+
return nil, err
210+
}
211+
212+
if chosenCluster != DevSpaceCloudHostedCluster {
213+
for _, cluster := range connectedClusters {
214+
if cluster.Name == chosenCluster {
215+
return cluster, nil
216+
}
217+
}
218+
}
219+
}
220+
221+
// Select a devspace cluster
222+
devSpaceClusters := make([]*latest.Cluster, 0, len(clusters))
223+
for _, cluster := range clusters {
224+
if cluster.Owner == nil {
225+
devSpaceClusters = append(devSpaceClusters, cluster)
226+
}
227+
}
228+
229+
if len(devSpaceClusters) == 1 {
230+
return devSpaceClusters[0], nil
231+
}
232+
233+
clusterNames := []string{}
234+
for _, cluster := range devSpaceClusters {
235+
clusterNames = append(clusterNames, cluster.Name)
236+
}
237+
238+
// Choose cluster
239+
chosenCluster, err := logger.Question(&survey.QuestionOptions{
240+
Question: "Which hosted DevSpace cluster should the space created in?",
241+
DefaultValue: clusterNames[0],
242+
Options: clusterNames,
243+
})
244+
if err != nil {
245+
return nil, err
246+
}
247+
248+
for _, cluster := range devSpaceClusters {
249+
if cluster.Name == chosenCluster {
250+
return cluster, nil
251+
}
252+
}
253+
254+
return nil, errors.New("No cluster selected")
255+
}
256+
257+
func createProject(p cloud.Provider) (int, error) {
258+
return p.Client().CreateProject("default")
259+
}

0 commit comments

Comments
 (0)