diff --git a/kube/client/client.go b/kube/client/client.go index 227688478..d9378bea4 100644 --- a/kube/client/client.go +++ b/kube/client/client.go @@ -22,6 +22,7 @@ import ( "context" "fmt" "io" + "time" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/utils" @@ -83,16 +84,6 @@ func (kc KubeClient) GetContainers(ctx context.Context, projectName string, all return result, nil } -func podToContainerSummary(pod corev1.Pod) compose.ContainerSummary { - return compose.ContainerSummary{ - ID: pod.GetObjectMeta().GetName(), - Name: pod.GetObjectMeta().GetName(), - Service: pod.GetObjectMeta().GetLabels()[compose.ServiceTag], - State: string(pod.Status.Phase), - Project: pod.GetObjectMeta().GetLabels()[compose.ProjectTag], - } -} - // GetLogs retrieves pod logs func (kc *KubeClient) GetLogs(ctx context.Context, projectName string, consumer compose.LogConsumer, follow bool) error { pods, err := kc.client.CoreV1().Pods(kc.namespace).List(ctx, metav1.ListOptions{ @@ -111,13 +102,81 @@ func (kc *KubeClient) GetLogs(ctx context.Context, projectName string, consumer eg.Go(func() error { r, err := request.Stream(ctx) - defer r.Close() // nolint errcheck if err != nil { return err } + + defer r.Close() // nolint errcheck _, err = io.Copy(w, r) return err }) } return eg.Wait() } + +// WaitForRunningPodState blocks until pods are in running state +func (kc KubeClient) WaitForPodState(ctx context.Context, projectName string, services []string, status string, timeout int) error { + + if timeout > 0 { + var t time.Duration + t = time.Duration(timeout) * time.Second + fmt.Println("Timeout ", t) + } + + selector := fmt.Sprintf("%s=%s", compose.ProjectTag, projectName) + + waitingForPhase := corev1.PodRunning + + switch status { + case compose.STARTING: + waitingForPhase = corev1.PodPending + case compose.UNKNOWN: + waitingForPhase = corev1.PodUnknown + } + + //fieldSelector := "status.phase=Running" + for { + time.Sleep(time.Duration(1) * time.Second) + timeout = timeout - 1 + if timeout <= 0 { + return fmt.Errorf("Deployment time out. Pods did not reach expected state.") + } + + pods, err := kc.client.CoreV1().Pods(kc.namespace).List(ctx, metav1.ListOptions{ + LabelSelector: selector, + }) + if err != nil { + return err + } + + servicePods := 0 + stateReached := true + for _, pod := range pods.Items { + + if status == compose.REMOVING { + if contains(services, pod.Labels[compose.ServiceTag]) { + servicePods = servicePods + 1 + } + + continue + } + + if pod.Status.Phase != waitingForPhase { + stateReached = false + + } + } + + if status == compose.REMOVING { + if len(pods.Items) > 0 { + continue + } + return nil + } + + if !stateReached { + continue + } + return nil + } +} diff --git a/kube/client/utils.go b/kube/client/utils.go new file mode 100644 index 000000000..ccc21810b --- /dev/null +++ b/kube/client/utils.go @@ -0,0 +1,43 @@ +// +build kube + +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "github.com/docker/compose-cli/api/compose" + corev1 "k8s.io/api/core/v1" +) + +func podToContainerSummary(pod corev1.Pod) compose.ContainerSummary { + return compose.ContainerSummary{ + ID: pod.GetObjectMeta().GetName(), + Name: pod.GetObjectMeta().GetName(), + Service: pod.GetObjectMeta().GetLabels()[compose.ServiceTag], + State: string(pod.Status.Phase), + Project: pod.GetObjectMeta().GetLabels()[compose.ProjectTag], + } +} + +func contains(slice []string, item string) bool { + for _, v := range slice { + if v == item { + return true + } + } + return false +} diff --git a/kube/compose.go b/kube/compose.go index 9ca2911fb..7518edc7f 100644 --- a/kube/compose.go +++ b/kube/compose.go @@ -91,7 +91,10 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options }) w.Event(progress.NewEvent(eventName, progress.Done, "")) - return err + + eventName = "Wait for pods to be running" + + return s.client.WaitForPodState(ctx, project.Name, project.ServiceNames(), compose.RUNNING, 10) } // Down executes the equivalent to a `compose down`