From ac8f0028bdde1e4f28dffd5eacec6368ea09de91 Mon Sep 17 00:00:00 2001 From: fabiankramm Date: Thu, 27 Jun 2019 08:19:01 +0200 Subject: [PATCH 1/4] Fix #586 --- cmd/enter.go | 13 +++++++ pkg/devspace/cloud/activate.go | 67 ++++++++++++++++++++++++++++++++++ pkg/devspace/cloud/cluster.go | 15 ++------ 3 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 pkg/devspace/cloud/activate.go diff --git a/cmd/enter.go b/cmd/enter.go index aa5c9ae2f0..ad3242a04b 100644 --- a/cmd/enter.go +++ b/cmd/enter.go @@ -1,12 +1,15 @@ package cmd import ( + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" + "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" latest "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" "github.com/devspace-cloud/devspace/pkg/devspace/kubectl" "github.com/devspace-cloud/devspace/pkg/devspace/services" "github.com/devspace-cloud/devspace/pkg/devspace/services/targetselector" "github.com/devspace-cloud/devspace/pkg/util/log" + "github.com/spf13/cobra" ) @@ -69,6 +72,16 @@ func (cmd *EnterCmd) Run(cobraCmd *cobra.Command, args []string) { var config *latest.Config if configutil.ConfigExists() { config = configutil.GetConfig() + + generatedConfig, err := generated.LoadConfig() + if err != nil { + log.Fatal(err) + } + + err = cloud.ActivateSpace(generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } } // Get kubectl client diff --git a/pkg/devspace/cloud/activate.go b/pkg/devspace/cloud/activate.go new file mode 100644 index 0000000000..bc568bba95 --- /dev/null +++ b/pkg/devspace/cloud/activate.go @@ -0,0 +1,67 @@ +package cloud + +import ( + "fmt" + "time" + + "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" + "github.com/devspace-cloud/devspace/pkg/util/log" + + "github.com/pkg/errors" +) + +// ActivateSpace ... +func ActivateSpace(generatedConfig *generated.Config, loop bool, log log.Logger) error { + if generatedConfig.CloudSpace != nil { + p, err := GetProvider(&generatedConfig.CloudSpace.ProviderName, log) + if err != nil { + return err + } + + space, err := p.GetSpace(generatedConfig.CloudSpace.SpaceID) + if err != nil { + return fmt.Errorf("Error retrieving Spaces details: %v", err) + } + + err = p.ActivateSpace(space.SpaceID, space.Cluster) + if err != nil { + return errors.Wrap(err, "active space") + } + + if loop { + go func() { + for { + time.Sleep(time.Minute * 5) + p.ActivateSpace(space.SpaceID, space.Cluster) + } + }() + } + } + + return nil +} + +// ActivateSpace creates a user cluster with the given name +func (p *Provider) ActivateSpace(spaceID int, cluster *Cluster) error { + key, err := p.GetClusterKey(cluster) + if err != nil { + return errors.Wrap(err, "get cluster key") + } + + // Do the request + err = p.GrapqhlRequest(` + mutation ($key:String, $spaceID: Int!){ + manager_activateSpace(key: $key, spaceID: $spaceID) + } + `, map[string]interface{}{ + "key": key, + "spaceID": spaceID, + }, &struct { + ActivateSpace bool `json:"manager_activateSpace"` + }{}) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/devspace/cloud/cluster.go b/pkg/devspace/cloud/cluster.go index 12b191b09d..352fdc7e90 100644 --- a/pkg/devspace/cloud/cluster.go +++ b/pkg/devspace/cloud/cluster.go @@ -219,10 +219,9 @@ func defaultClusterSpaceDomain(p *Provider, client kubernetes.Interface, useHost defer log.StopWait() now := time.Now() - hostname := "" - ip := "" - for time.Since(now) < waitTimeout && hostname == "" && ip == "" { + Outer: + for time.Since(now) < waitTimeout { // Get loadbalancer services, err := client.CoreV1().Services(constants.DevSpaceCloudNamespace).List(metav1.ListOptions{}) if err != nil { @@ -234,19 +233,13 @@ func defaultClusterSpaceDomain(p *Provider, client kubernetes.Interface, useHost if service.Spec.Type == v1.ServiceTypeLoadBalancer { for _, ingress := range service.Status.LoadBalancer.Ingress { if ingress.Hostname != "" { - hostname = ingress.Hostname + break Outer } if ingress.IP != "" { - ip = ingress.IP + break Outer } - - break } } - - if hostname != "" || ip != "" { - break - } } time.Sleep(5 * time.Second) From 02ea713fc5ea3d7c307fb46cd1462cfba4844f7d Mon Sep 17 00:00:00 2001 From: fabiankramm Date: Thu, 27 Jun 2019 08:30:43 +0200 Subject: [PATCH 2/4] Fix schema issue --- pkg/devspace/config/versions/latest/schema.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/devspace/config/versions/latest/schema.go b/pkg/devspace/config/versions/latest/schema.go index 97891e236e..acd92494e6 100644 --- a/pkg/devspace/config/versions/latest/schema.go +++ b/pkg/devspace/config/versions/latest/schema.go @@ -3,7 +3,6 @@ package latest import ( "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/config" "github.com/devspace-cloud/devspace/pkg/util/ptr" - v1 "k8s.io/api/core/v1" ) // Version is the current api version @@ -163,10 +162,10 @@ type RollingUpdateConfig struct { // VolumeConfig holds the configuration for a specific volume type VolumeConfig struct { - Name *string `yaml:"name,omitempty"` - Size *string `yaml:"size,omitempty"` - ConfigMap *v1.ConfigMapVolumeSource `yaml:"configMap,omitempty"` - Secret *v1.SecretVolumeSource `yaml:"secret,omitempty"` + Name *string `yaml:"name,omitempty"` + Size *string `yaml:"size,omitempty"` + ConfigMap *map[interface{}]interface{} `yaml:"configMap,omitempty"` + Secret *map[interface{}]interface{} `yaml:"secret,omitempty"` } // ServiceConfig holds the configuration of a component service From f75473eef0009a8e31b136041f1171a8d853da83 Mon Sep 17 00:00:00 2001 From: fabiankramm Date: Thu, 27 Jun 2019 16:39:36 +0200 Subject: [PATCH 3/4] Sleep mode --- cmd/analyze.go | 13 ++++ cmd/deploy.go | 7 ++ cmd/dev.go | 7 ++ cmd/enter.go | 2 +- cmd/logs.go | 13 ++++ cmd/open.go | 11 ++++ cmd/purge.go | 7 ++ cmd/sync.go | 13 ++++ cmd/use/space.go | 6 ++ pkg/devspace/cloud/activate.go | 67 ------------------- pkg/devspace/cloud/resume.go | 117 +++++++++++++++++++++++++++++++++ 11 files changed, 195 insertions(+), 68 deletions(-) delete mode 100644 pkg/devspace/cloud/activate.go create mode 100644 pkg/devspace/cloud/resume.go diff --git a/cmd/analyze.go b/cmd/analyze.go index e18a21aa14..9908724b61 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -2,7 +2,9 @@ package cmd import ( "github.com/devspace-cloud/devspace/pkg/devspace/analyze" + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" + "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" latest "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" "github.com/devspace-cloud/devspace/pkg/devspace/kubectl" "github.com/devspace-cloud/devspace/pkg/util/log" @@ -55,6 +57,17 @@ func (cmd *AnalyzeCmd) RunAnalyze(cobraCmd *cobra.Command, args []string) { var devSpaceConfig *latest.Config if configExists { devSpaceConfig = configutil.GetConfig() + + generatedConfig, err := generated.LoadConfig() + if err != nil { + log.Fatal(err) + } + + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(devSpaceConfig, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } } // Create kubectl client diff --git a/cmd/deploy.go b/cmd/deploy.go index d223c2580e..3ee3623180 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/devspace-cloud/devspace/pkg/devspace/build" + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" latest "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" @@ -99,6 +100,12 @@ func (cmd *DeployCmd) Run(cobraCmd *cobra.Command, args []string) { // Prepare the config config := cmd.loadConfig(generatedConfig) + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(config, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } + // Create kubectl client client, err := kubectl.NewClientWithContextSwitch(config, cmd.SwitchContext) if err != nil { diff --git a/cmd/dev.go b/cmd/dev.go index 3a36dca6bf..815a06c801 100644 --- a/cmd/dev.go +++ b/cmd/dev.go @@ -8,6 +8,7 @@ import ( "time" "github.com/devspace-cloud/devspace/pkg/devspace/build" + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/dependency" deploy "github.com/devspace-cloud/devspace/pkg/devspace/deploy/util" "github.com/devspace-cloud/devspace/pkg/devspace/services/targetselector" @@ -125,6 +126,12 @@ func (cmd *DevCmd) Run(cobraCmd *cobra.Command, args []string) { // Get the config config := cmd.loadConfig(generatedConfig) + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(config, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } + // Create kubectl client and switch context if specified client, err := kubectl.NewClientWithContextSwitch(config, cmd.SwitchContext) if err != nil { diff --git a/cmd/enter.go b/cmd/enter.go index ad3242a04b..a95ddd0b71 100644 --- a/cmd/enter.go +++ b/cmd/enter.go @@ -78,7 +78,7 @@ func (cmd *EnterCmd) Run(cobraCmd *cobra.Command, args []string) { log.Fatal(err) } - err = cloud.ActivateSpace(generatedConfig, true, log.GetInstance()) + err = cloud.ResumeSpace(config, generatedConfig, true, log.GetInstance()) if err != nil { log.Fatal(err) } diff --git a/cmd/logs.go b/cmd/logs.go index bfdc22cabc..866c8692c3 100644 --- a/cmd/logs.go +++ b/cmd/logs.go @@ -1,7 +1,9 @@ package cmd import ( + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" + "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" latest "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" "github.com/devspace-cloud/devspace/pkg/devspace/kubectl" "github.com/devspace-cloud/devspace/pkg/devspace/services" @@ -68,6 +70,17 @@ func (cmd *LogsCmd) RunLogs(cobraCmd *cobra.Command, args []string) { var config *latest.Config if configutil.ConfigExists() { config = configutil.GetConfig() + + generatedConfig, err := generated.LoadConfig() + if err != nil { + log.Fatal(err) + } + + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(config, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } } // Get kubectl client diff --git a/cmd/open.go b/cmd/open.go index 2436de0fc9..8c2c308c0f 100644 --- a/cmd/open.go +++ b/cmd/open.go @@ -142,6 +142,17 @@ func (cmd *OpenCmd) RunOpen(cobraCmd *cobra.Command, args []string) { var devspaceConfig *latest.Config if configExists { devspaceConfig = configutil.GetConfig() + + generatedConfig, err := generated.LoadConfig() + if err != nil { + log.Fatal(err) + } + + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(devspaceConfig, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } } namespace, err := configutil.GetDefaultNamespace(devspaceConfig) if err != nil { diff --git a/cmd/purge.go b/cmd/purge.go index 5eb17a880c..f522cbdd36 100644 --- a/cmd/purge.go +++ b/cmd/purge.go @@ -3,6 +3,7 @@ package cmd import ( "strings" + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" latest "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" @@ -74,6 +75,12 @@ func (cmd *PurgeCmd) Run(cobraCmd *cobra.Command, args []string) { // Get the config config := cmd.loadConfig(generatedConfig) + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(config, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } + kubectl, err := kubectl.NewClient(config) if err != nil { log.Fatalf("Unable to create new kubectl client: %v", err) diff --git a/cmd/sync.go b/cmd/sync.go index 27d025ceeb..a3ebc973f3 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -1,7 +1,9 @@ package cmd import ( + "github.com/devspace-cloud/devspace/pkg/devspace/cloud" "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" + "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" latest "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" "github.com/devspace-cloud/devspace/pkg/devspace/services" "github.com/devspace-cloud/devspace/pkg/devspace/services/targetselector" @@ -67,6 +69,17 @@ func (cmd *SyncCmd) Run(cobraCmd *cobra.Command, args []string) { var config *latest.Config if configutil.ConfigExists() { config = configutil.GetConfig() + + generatedConfig, err := generated.LoadConfig() + if err != nil { + log.Fatal(err) + } + + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(config, generatedConfig, true, log.GetInstance()) + if err != nil { + log.Fatal(err) + } } // Build params diff --git a/cmd/use/space.go b/cmd/use/space.go index abf4a28151..425792865e 100644 --- a/cmd/use/space.go +++ b/cmd/use/space.go @@ -143,6 +143,12 @@ func (cmd *spaceCmd) RunUseSpace(cobraCmd *cobra.Command, args []string) { if err != nil { log.Fatal(err) } + + // Signal that we are working on the space if there is any + err = cloud.ResumeSpace(configutil.GetConfig(), generatedConfig, false, log.GetInstance()) + if err != nil { + log.Fatal(err) + } } log.Donef("Successfully configured config to use space %s", space.Name) diff --git a/pkg/devspace/cloud/activate.go b/pkg/devspace/cloud/activate.go deleted file mode 100644 index bc568bba95..0000000000 --- a/pkg/devspace/cloud/activate.go +++ /dev/null @@ -1,67 +0,0 @@ -package cloud - -import ( - "fmt" - "time" - - "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" - "github.com/devspace-cloud/devspace/pkg/util/log" - - "github.com/pkg/errors" -) - -// ActivateSpace ... -func ActivateSpace(generatedConfig *generated.Config, loop bool, log log.Logger) error { - if generatedConfig.CloudSpace != nil { - p, err := GetProvider(&generatedConfig.CloudSpace.ProviderName, log) - if err != nil { - return err - } - - space, err := p.GetSpace(generatedConfig.CloudSpace.SpaceID) - if err != nil { - return fmt.Errorf("Error retrieving Spaces details: %v", err) - } - - err = p.ActivateSpace(space.SpaceID, space.Cluster) - if err != nil { - return errors.Wrap(err, "active space") - } - - if loop { - go func() { - for { - time.Sleep(time.Minute * 5) - p.ActivateSpace(space.SpaceID, space.Cluster) - } - }() - } - } - - return nil -} - -// ActivateSpace creates a user cluster with the given name -func (p *Provider) ActivateSpace(spaceID int, cluster *Cluster) error { - key, err := p.GetClusterKey(cluster) - if err != nil { - return errors.Wrap(err, "get cluster key") - } - - // Do the request - err = p.GrapqhlRequest(` - mutation ($key:String, $spaceID: Int!){ - manager_activateSpace(key: $key, spaceID: $spaceID) - } - `, map[string]interface{}{ - "key": key, - "spaceID": spaceID, - }, &struct { - ActivateSpace bool `json:"manager_activateSpace"` - }{}) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/devspace/cloud/resume.go b/pkg/devspace/cloud/resume.go new file mode 100644 index 0000000000..cd0aeafaa0 --- /dev/null +++ b/pkg/devspace/cloud/resume.go @@ -0,0 +1,117 @@ +package cloud + +import ( + "fmt" + "time" + + "github.com/devspace-cloud/devspace/pkg/devspace/config/configutil" + "github.com/devspace-cloud/devspace/pkg/devspace/config/generated" + "github.com/devspace-cloud/devspace/pkg/devspace/config/versions/latest" + "github.com/devspace-cloud/devspace/pkg/devspace/kubectl" + "github.com/devspace-cloud/devspace/pkg/util/log" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/pkg/errors" +) + +// ResumeSpace signals the cloud that we are currently working on the space and resumes it if it's currently paused +func ResumeSpace(config *latest.Config, generatedConfig *generated.Config, loop bool, log log.Logger) error { + if generatedConfig.CloudSpace == nil { + return nil + } + + p, err := GetProvider(&generatedConfig.CloudSpace.ProviderName, log) + if err != nil { + return err + } + + space, err := p.GetSpace(generatedConfig.CloudSpace.SpaceID) + if err != nil { + return fmt.Errorf("Error retrieving Spaces details: %v", err) + } + + resumed, err := p.ResumeSpace(space.SpaceID, space.Cluster) + if err != nil { + return errors.Wrap(err, "active space") + } + + // We will wait a little bit till the space has resumed + if resumed { + log.StartWait("Resuming space") + defer log.StopWait() + + // Give the controllers some time to create the pods + time.Sleep(time.Second * 3) + + // Create kubectl client and switch context if specified + client, err := kubectl.NewClient(config) + if err != nil { + return fmt.Errorf("Unable to create new kubectl client: %v", err) + } + + namespace, err := configutil.GetDefaultNamespace(config) + if err != nil { + return err + } + + maxWait := time.Minute * 5 + start := time.Now() + + for time.Now().Sub(start) <= maxWait { + pods, err := client.CoreV1().Pods(namespace).List(metav1.ListOptions{}) + if err != nil { + return errors.Wrap(err, "list pods") + } + + continueWaiting := false + for _, pod := range pods.Items { + for _, containerStatus := range pod.Status.ContainerStatuses { + if containerStatus.State.Waiting != nil { + continueWaiting = true + } + } + } + + if !continueWaiting { + break + } + } + } + + if loop { + go func() { + for { + time.Sleep(time.Minute * 3) + p.ResumeSpace(space.SpaceID, space.Cluster) + } + }() + } + + return nil +} + +// ResumeSpace resumes a space if its sleeping and sets the last activity to the current timestamp +func (p *Provider) ResumeSpace(spaceID int, cluster *Cluster) (bool, error) { + key, err := p.GetClusterKey(cluster) + if err != nil { + return false, errors.Wrap(err, "get cluster key") + } + + // Do the request + response := &struct { + ResumeSpace bool `json:"manager_resumeSpace"` + }{} + err = p.GrapqhlRequest(` + mutation ($key:String, $spaceID: Int!){ + manager_resumeSpace(key: $key, spaceID: $spaceID) + } + `, map[string]interface{}{ + "key": key, + "spaceID": spaceID, + }, response) + if err != nil { + return false, err + } + + return response.ResumeSpace, nil +} From a7417f97167204ce8a416e216c14a4061cb9222f Mon Sep 17 00:00:00 2001 From: fabiankramm Date: Thu, 27 Jun 2019 16:42:12 +0200 Subject: [PATCH 4/4] Throttle pod list requests --- pkg/devspace/cloud/resume.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/devspace/cloud/resume.go b/pkg/devspace/cloud/resume.go index cd0aeafaa0..e79ff488f6 100644 --- a/pkg/devspace/cloud/resume.go +++ b/pkg/devspace/cloud/resume.go @@ -75,6 +75,8 @@ func ResumeSpace(config *latest.Config, generatedConfig *generated.Config, loop if !continueWaiting { break } + + time.Sleep(1 * time.Second) } }