Skip to content

Commit 92f2e8b

Browse files
committed
refactor: print cause why sync restarted
1 parent 07b7916 commit 92f2e8b

File tree

7 files changed

+137
-82
lines changed

7 files changed

+137
-82
lines changed

pkg/devspace/config/generated/schema.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type DeploymentCache struct {
5353

5454
HelmOverridesHash string `yaml:"helmOverridesHash,omitempty"`
5555
HelmChartHash string `yaml:"helmChartHash,omitempty"`
56+
HelmValuesHash string `yaml:"helmValuesHash,omitempty"`
5657
HelmReleaseRevision string `yaml:"helmReleaseRevision,omitempty"`
5758

5859
KubectlManifestsHash string `yaml:"kubectlManifestsHash,omitempty"`

pkg/devspace/deploy/deployer/helm/deploy.go

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,21 @@ func (d *DeployConfig) Deploy(forceDeploy bool, builtImages map[string]string) (
7070
}
7171
}
7272

73+
// Get deployment values
74+
redeploy, deployValues, err := d.getDeploymentValues(builtImages)
75+
if err != nil {
76+
return false, err
77+
}
78+
79+
// Check deployment values for changes
80+
deployValuesBytes, err := yaml.Marshal(deployValues)
81+
if err != nil {
82+
return false, errors.Wrap(err, "marshal deployment values")
83+
}
84+
deployValuesHash := hashpkg.String(string(deployValuesBytes))
85+
7386
// Check if redeploying is necessary
74-
forceDeploy = forceDeploy || deployCache.HelmOverridesHash != helmOverridesHash || deployCache.HelmChartHash != hash || deployCache.DeploymentConfigHash != deploymentConfigHash
87+
forceDeploy = forceDeploy || redeploy || deployCache.HelmValuesHash != deployValuesHash || deployCache.HelmOverridesHash != helmOverridesHash || deployCache.HelmChartHash != hash || deployCache.DeploymentConfigHash != deploymentConfigHash
7588
if !forceDeploy {
7689
releases, err := d.Helm.ListReleases(d.DeploymentConfig.Helm)
7790
if err != nil {
@@ -88,38 +101,69 @@ func (d *DeployConfig) Deploy(forceDeploy bool, builtImages map[string]string) (
88101
}
89102

90103
// Deploy
91-
wasDeployed, release, err := d.internalDeploy(forceDeploy, builtImages, nil)
92-
if err != nil {
93-
return false, err
94-
}
104+
if forceDeploy {
105+
release, err := d.internalDeploy(deployValues, nil)
106+
if err != nil {
107+
return false, err
108+
}
95109

96-
// Update config
97-
if wasDeployed {
98110
deployCache.DeploymentConfigHash = deploymentConfigHash
99111
deployCache.HelmChartHash = hash
112+
deployCache.HelmValuesHash = deployValuesHash
100113
deployCache.HelmOverridesHash = helmOverridesHash
101114
if release != nil {
102115
deployCache.HelmReleaseRevision = release.Revision
103116
}
117+
118+
return true, nil
119+
}
120+
121+
return false, nil
122+
}
123+
124+
func (d *DeployConfig) internalDeploy(overwriteValues map[interface{}]interface{}, out io.Writer) (*types.Release, error) {
125+
var (
126+
releaseName = d.DeploymentConfig.Name
127+
releaseNamespace = d.DeploymentConfig.Namespace
128+
)
129+
130+
if out != nil {
131+
str, err := d.Helm.Template(releaseName, releaseNamespace, overwriteValues, d.DeploymentConfig.Helm)
132+
if err != nil {
133+
return nil, err
134+
}
135+
136+
_, _ = out.Write([]byte("\n" + str + "\n"))
137+
return nil, nil
138+
}
139+
140+
d.Log.StartWait(fmt.Sprintf("Deploying chart %s (%s) with helm", d.DeploymentConfig.Helm.Chart.Name, d.DeploymentConfig.Name))
141+
defer d.Log.StopWait()
142+
143+
// Deploy chart
144+
appRelease, err := d.Helm.InstallChart(releaseName, releaseNamespace, overwriteValues, d.DeploymentConfig.Helm)
145+
if err != nil {
146+
return nil, errors.Errorf("Unable to deploy helm chart: %v\nRun `%s` and `%s` to recreate the chart", err, ansi.Color("devspace purge -d "+d.DeploymentConfig.Name, "white+b"), ansi.Color("devspace deploy", "white+b"))
147+
}
148+
149+
// Print revision
150+
if appRelease != nil {
151+
d.Log.Donef("Deployed helm chart (Release revision: %s)", appRelease.Revision)
104152
} else {
105-
return false, nil
153+
d.Log.Done("Deployed helm chart")
106154
}
107155

108-
return true, nil
156+
return appRelease, nil
109157
}
110158

111-
func (d *DeployConfig) internalDeploy(forceDeploy bool, builtImages map[string]string, out io.Writer) (bool, *types.Release, error) {
159+
func (d *DeployConfig) getDeploymentValues(builtImages map[string]string) (bool, map[interface{}]interface{}, error) {
112160
var (
113-
releaseName = d.DeploymentConfig.Name
114161
chartPath = d.DeploymentConfig.Helm.Chart.Name
115162
chartValuesPath = filepath.Join(chartPath, "values.yaml")
116163
overwriteValues = map[interface{}]interface{}{}
117164
shouldRedeploy = false
118165
)
119166

120-
// Get release namespace
121-
releaseNamespace := d.DeploymentConfig.Namespace
122-
123167
// Check if its a local chart
124168
_, err := os.Stat(chartValuesPath)
125169
if err == nil {
@@ -159,7 +203,7 @@ func (d *DeployConfig) internalDeploy(forceDeploy bool, builtImages map[string]s
159203
}
160204
shouldRedeploy = shouldRedeploy || redeploy
161205
}
162-
206+
163207
merge.Values(overwriteValues).MergeInto(overwriteValuesFromPath)
164208
}
165209
}
@@ -178,41 +222,5 @@ func (d *DeployConfig) internalDeploy(forceDeploy bool, builtImages map[string]s
178222
merge.Values(overwriteValues).MergeInto(d.DeploymentConfig.Helm.Values)
179223
}
180224

181-
// Add devspace specific values
182-
if !forceDeploy && shouldRedeploy {
183-
forceDeploy = true
184-
}
185-
186-
// Deployment is not necessary
187-
if !forceDeploy {
188-
return false, nil, nil
189-
}
190-
191-
if out != nil {
192-
str, err := d.Helm.Template(releaseName, releaseNamespace, overwriteValues, d.DeploymentConfig.Helm)
193-
if err != nil {
194-
return false, nil, err
195-
}
196-
197-
_, _ = out.Write([]byte("\n" + str + "\n"))
198-
return true, nil, nil
199-
}
200-
201-
d.Log.StartWait(fmt.Sprintf("Deploying chart %s (%s) with helm", d.DeploymentConfig.Helm.Chart.Name, d.DeploymentConfig.Name))
202-
defer d.Log.StopWait()
203-
204-
// Deploy chart
205-
appRelease, err := d.Helm.InstallChart(releaseName, releaseNamespace, overwriteValues, d.DeploymentConfig.Helm)
206-
if err != nil {
207-
return false, nil, errors.Errorf("Unable to deploy helm chart: %v\nRun `%s` and `%s` to recreate the chart", err, ansi.Color("devspace purge -d "+d.DeploymentConfig.Name, "white+b"), ansi.Color("devspace deploy", "white+b"))
208-
}
209-
210-
// Print revision
211-
if appRelease != nil {
212-
d.Log.Donef("Deployed helm chart (Release revision: %s)", appRelease.Revision)
213-
} else {
214-
d.Log.Done("Deployed helm chart")
215-
}
216-
217-
return true, appRelease, nil
225+
return shouldRedeploy, overwriteValues, nil
218226
}

pkg/devspace/deploy/deployer/helm/render.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import (
66

77
// Render runs a `helm template`
88
func (d *DeployConfig) Render(builtImages map[string]string, out io.Writer) error {
9-
_, _, err := d.internalDeploy(true, builtImages, out)
9+
_, deployValues, err := d.getDeploymentValues(builtImages)
10+
if err != nil {
11+
return err
12+
}
13+
14+
_, err = d.internalDeploy(deployValues, out)
1015
return err
1116
}

pkg/devspace/services/port_forwarding.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
runtimevar "github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/runtime"
77
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
8+
"github.com/loft-sh/devspace/pkg/devspace/services/synccontroller"
89
"strconv"
910
"strings"
1011
"time"
@@ -189,6 +190,7 @@ func (serviceClient *client) startForwarding(portForwarding *latest.PortForwardi
189190
case err := <-errorChan:
190191
if err != nil {
191192
fileLog.Errorf("Portforwarding restarting, because: %v", err)
193+
synccontroller.PrintPodError(context.TODO(), serviceClient.KubeClient(), pod, fileLog)
192194
pf.Close()
193195
hook.LogExecuteHooks(serviceClient.KubeClient(), serviceClient.Config(), serviceClient.Dependencies(), map[string]interface{}{
194196
"port_forwarding_config": portForwarding,

pkg/devspace/services/reverse_port_forwarding.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func (serviceClient *client) startReversePortForwarding(portForwarding *latest.P
7474
case err := <-errorChan:
7575
if err != nil {
7676
fileLog.Errorf("Reverse portforwarding restarting, because: %v", err)
77+
synccontroller.PrintPodError(context.TODO(), serviceClient.KubeClient(), container.Pod, fileLog)
7778
close(closeChan)
7879
_ = stdinWriter.Close()
7980
_ = stdoutWriter.Close()

pkg/devspace/services/synccontroller/controller.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import (
66
"fmt"
77
runtimevar "github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/runtime"
88
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
9+
"github.com/loft-sh/devspace/pkg/devspace/kubectl/selector"
910
"io"
11+
kerrors "k8s.io/apimachinery/pkg/api/errors"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1013
"os"
1114
"path/filepath"
1215
"runtime"
@@ -104,7 +107,7 @@ func (c *controller) startWithWait(options *Options, log logpkg.Logger) error {
104107
}
105108

106109
// start the sync
107-
client, err := c.startSync(options, onInitUploadDone, onInitDownloadDone, onDone, onError, log)
110+
client, pod, err := c.startSync(options, onInitUploadDone, onInitDownloadDone, onDone, onError, log)
108111
if err != nil {
109112
pluginErr := hook.ExecuteHooks(c.client, c.config, c.dependencies, map[string]interface{}{
110113
"sync_config": options.SyncConfig,
@@ -185,6 +188,7 @@ func (c *controller) startWithWait(options *Options, log logpkg.Logger) error {
185188
}, options.SyncLog, hook.EventsForSingle("restart:sync", options.SyncConfig.Name).With("sync.restart")...)
186189

187190
options.SyncLog.Info("Restarting sync...")
191+
PrintPodError(context.TODO(), c.client, pod.Pod, options.SyncLog)
188192
for {
189193
err := c.startWithWait(options, options.SyncLog)
190194
if err != nil {
@@ -218,6 +222,25 @@ func (c *controller) startWithWait(options *Options, log logpkg.Logger) error {
218222

219223
return nil
220224
}
225+
226+
func PrintPodError(ctx context.Context, kubeClient kubectl.Client, pod *v1.Pod, log logpkg.Logger) {
227+
// check if pod still exists
228+
newPod, err := kubeClient.KubeClient().CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
229+
if err != nil {
230+
if kerrors.IsNotFound(err) {
231+
log.Errorf("Restarted because old pod %s/%s seems to be erased", pod.Namespace, pod.Name)
232+
return
233+
}
234+
235+
return
236+
}
237+
238+
podStatus := kubectl.GetPodStatus(newPod)
239+
if podStatus != "Running" {
240+
log.Errorf("Restarted because old pod %s/%s has status %s", pod.Namespace, pod.Name, podStatus)
241+
}
242+
}
243+
221244
func realWorkDir() (string, error) {
222245
if runtime.GOOS == "darwin" {
223246
if pwd, present := os.LookupEnv("PWD"); present {
@@ -229,15 +252,15 @@ func realWorkDir() (string, error) {
229252
return ".", nil
230253
}
231254

232-
func (c *controller) startSync(options *Options, onInitUploadDone chan struct{}, onInitDownloadDone chan struct{}, onDone chan struct{}, onError chan error, log logpkg.Logger) (*sync.Sync, error) {
255+
func (c *controller) startSync(options *Options, onInitUploadDone chan struct{}, onInitDownloadDone chan struct{}, onDone chan struct{}, onError chan error, log logpkg.Logger) (*sync.Sync, *selector.SelectedPodContainer, error) {
233256
options.TargetOptions.SkipInitContainers = true
234257
var (
235258
syncConfig = options.SyncConfig
236259
)
237260

238261
localPath, err := realWorkDir()
239262
if err != nil {
240-
return nil, err
263+
return nil, nil, err
241264
}
242265

243266
if syncConfig.LocalSubPath != "" {
@@ -247,20 +270,20 @@ func (c *controller) startSync(options *Options, onInitUploadDone chan struct{},
247270
_, err = os.Stat(localPath)
248271
if err != nil {
249272
if !os.IsNotExist(err) {
250-
return nil, err
273+
return nil, nil, err
251274
}
252275

253276
err = os.MkdirAll(localPath, os.ModePerm)
254277
if err != nil {
255-
return nil, err
278+
return nil, nil, err
256279
}
257280
}
258281

259282
options.TargetOptions.ImageSelector = []imageselector.ImageSelector{}
260283
if syncConfig.ImageSelector != "" {
261284
imageSelector, err := runtimevar.NewRuntimeResolver(true).FillRuntimeVariablesAsImageSelector(syncConfig.ImageSelector, c.config, c.dependencies)
262285
if err != nil {
263-
return nil, err
286+
return nil, nil, err
264287
}
265288

266289
options.TargetOptions.ImageSelector = append(options.TargetOptions.ImageSelector, *imageSelector)
@@ -269,18 +292,18 @@ func (c *controller) startSync(options *Options, onInitUploadDone chan struct{},
269292
log.Info("Waiting for containers to start...")
270293
container, err := targetselector.NewTargetSelector(c.client).SelectSingleContainer(context.TODO(), options.TargetOptions, log)
271294
if err != nil {
272-
return nil, errors.Errorf("Error selecting pod: %v", err)
295+
return nil, nil, errors.Errorf("Error selecting pod: %v", err)
273296
}
274297

275298
log.Info("Starting sync...")
276299
syncClient, err := c.initClient(container.Pod, container.Container.Name, syncConfig, options.Verbose, options.SyncLog)
277300
if err != nil {
278-
return nil, errors.Wrap(err, "start sync")
301+
return nil, nil, errors.Wrap(err, "start sync")
279302
}
280303

281304
err = syncClient.Start(onInitUploadDone, onInitDownloadDone, onDone, onError)
282305
if err != nil {
283-
return nil, errors.Errorf("Sync error: %v", err)
306+
return nil, nil, errors.Errorf("Sync error: %v", err)
284307
}
285308

286309
containerPath := "."
@@ -289,7 +312,7 @@ func (c *controller) startSync(options *Options, onInitUploadDone chan struct{},
289312
}
290313

291314
log.Donef("Sync started on %s <-> %s (Pod: %s/%s)", syncClient.LocalPath, containerPath, container.Pod.Namespace, container.Pod.Name)
292-
return syncClient, nil
315+
return syncClient, container, nil
293316
}
294317

295318
func (c *controller) initClient(pod *v1.Pod, container string, syncConfig *latest.SyncConfig, verbose bool, customLog logpkg.Logger) (*sync.Sync, error) {

0 commit comments

Comments
 (0)