Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pkg/skaffold/hooks/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (r deployRunner) run(ctx context.Context, out io.Writer, hooks []latest.Dep
output.Default.Fprintln(out, fmt.Sprintf("Starting %s hooks...", phase))
}
env := r.getEnv(manifestsNs)
for _, h := range hooks {
for i, h := range hooks {
if h.HostHook != nil {
hook := hostHook{*h.HostHook, env}
if err := hook.run(ctx, nil, out); err != nil && !errors.Is(err, &Skip{}) {
Expand All @@ -119,7 +119,7 @@ func (r deployRunner) run(ctx context.Context, out io.Writer, hooks []latest.Dep
hook := containerHook{
cfg: latest.ContainerHook{Command: h.ContainerHook.Command},
cli: r.cli,
selector: filterContainersSelector(r.visitedContainers, phase, namePatternSelector(h.ContainerHook.PodName, h.ContainerHook.ContainerName)),
selector: filterContainersSelector(r.visitedContainers, phase, i, namePatternSelector(h.ContainerHook.PodName, h.ContainerHook.ContainerName)),
namespaces: *r.namespaces,
formatter: r.formatter,
}
Expand All @@ -135,9 +135,9 @@ func (r deployRunner) run(ctx context.Context, out io.Writer, hooks []latest.Dep
}

// filterContainersSelector filters the containers that have already been processed from a previous deploy iteration
func filterContainersSelector(visitedContainers *sync.Map, phase phase, selector containerSelector) containerSelector {
func filterContainersSelector(visitedContainers *sync.Map, phase phase, hookIndex int, selector containerSelector) containerSelector {
return func(p corev1.Pod, c corev1.Container) (bool, error) {
key := fmt.Sprintf("%s:%s:%s", phase, p.GetName(), c.Name)
key := fmt.Sprintf("%s:%d:%s:%s:%s", phase, hookIndex, p.GetNamespace(), p.GetName(), c.Name)
if _, found := visitedContainers.LoadOrStore(key, struct{}{}); found {
return false, nil
}
Expand Down
20 changes: 18 additions & 2 deletions pkg/skaffold/hooks/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util"
"github.com/GoogleContainerTools/skaffold/v2/testutil"
"github.com/GoogleContainerTools/skaffold/v2/testutil/concurrency"
)

const testKubeContext = "context1"
Expand Down Expand Up @@ -82,12 +83,22 @@ func TestDeployHooks(t *testing.T) {
ContainerName: "container1",
},
},
{
ContainerHook: &latest.NamedContainerHook{
ContainerHook: latest.ContainerHook{
Command: []string{"bar", "post-hook-2"},
},
PodName: "pod1",
ContainerName: "container1",
},
},
},
}
preHostHookOut := "pre-hook running with SKAFFOLD_RUN_ID=run_id,SKAFFOLD_KUBE_CONTEXT=context1,SKAFFOLD_NAMESPACES=np1,np2"
preContainerHookOut := "container pre-hook succeeded"
postHostHookOut := "post-hook running with SKAFFOLD_RUN_ID=run_id,SKAFFOLD_KUBE_CONTEXT=context1,SKAFFOLD_NAMESPACES=np1,np2"
postContainerHookOut := "container post-hook succeeded"
postContainerHook2Out := "container post-hook-2 succeeded"

deployer := latest.KubectlDeploy{
LifecycleHooks: hooks,
Expand All @@ -98,8 +109,12 @@ func TestDeployHooks(t *testing.T) {
runner := NewDeployRunner(&kubectl.CLI{KubeContext: testKubeContext}, deployer.LifecycleHooks, &namespaces, formatter, opts, nil)

t.Override(&util.DefaultExecCommand,
testutil.CmdRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo pre-hook", preContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo post-hook", postContainerHookOut))
concurrency.CmdRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo pre-hook", preContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np2 -c container1 -- foo pre-hook", preContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo post-hook", postContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np2 -c container1 -- foo post-hook", postContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- bar post-hook-2", postContainerHook2Out).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np2 -c container1 -- bar post-hook-2", postContainerHook2Out))
t.Override(&kubernetesclient.Client, fakeKubernetesClient)
var preOut, postOut bytes.Buffer
err := runner.RunPreHooks(context.Background(), &preOut)
Expand All @@ -110,6 +125,7 @@ func TestDeployHooks(t *testing.T) {
t.CheckNoError(err)
t.CheckContains(postHostHookOut, postOut.String())
t.CheckContains(postContainerHookOut, postOut.String())
t.CheckContains(postContainerHook2Out, postOut.String())
})
}

Expand Down
24 changes: 20 additions & 4 deletions pkg/skaffold/hooks/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util"
"github.com/GoogleContainerTools/skaffold/v2/testutil"
"github.com/GoogleContainerTools/skaffold/v2/testutil/concurrency"
)

func TestSyncHooks(t *testing.T) {
Expand Down Expand Up @@ -102,8 +103,10 @@ func TestSyncHooks(t *testing.T) {
runner := NewSyncRunner(&kubectl.CLI{KubeContext: kubeContext}, artifact.ImageName, image, namespaces, formatter, artifact.Sync.LifecycleHooks, opts)

t.Override(&util.DefaultExecCommand,
testutil.CmdRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo pre-hook", preContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo post-hook", postContainerHookOut))
concurrency.CmdRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo pre-hook", preContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np2 -c container1 -- foo pre-hook", preContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo post-hook", postContainerHookOut).
AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np2 -c container1 -- foo post-hook", postContainerHookOut))
t.Override(&kubernetesclient.Client, fakeKubernetesClient)
var preOut, postOut bytes.Buffer
err = runner.RunPreHooks(context.Background(), &preOut)
Expand All @@ -118,7 +121,7 @@ func TestSyncHooks(t *testing.T) {
}

func fakeKubernetesClient(string) (kubernetes.Interface, error) {
pod := &corev1.Pod{
pod1Np1 := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Namespace: "np1",
Expand All @@ -137,7 +140,20 @@ func fakeKubernetesClient(string) (kubernetes.Interface, error) {
},
}},
}
return fakeclient.NewSimpleClientset(pod), nil
pod1Np2 := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Namespace: "np2",
},
Status: corev1.PodStatus{Phase: corev1.PodRunning},
Spec: corev1.PodSpec{Containers: []corev1.Container{
{
Name: "container1",
Image: "gcr.io/foo/img1:latest",
},
}},
}
return fakeclient.NewSimpleClientset(pod1Np1, pod1Np2), nil
}

type mockLogFormatter struct{}
Expand Down