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
34 changes: 34 additions & 0 deletions cmd/diff/diffprocessor/function_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"os"
"strings"
"time"

Expand All @@ -48,6 +49,35 @@ type FunctionProvider interface {
Cleanup(ctx context.Context) error
}

// EnvDockerNetwork is the environment variable that specifies which Docker
// network function containers should join. This is needed when crossplane-diff
// runs inside a Docker container (e.g. a GitHub Actions container job) so that
// function containers are on the same network and reachable via container IP.
const EnvDockerNetwork = "CROSSPLANE_DIFF_DOCKER_NETWORK"

// annotationRuntimeDockerNetwork is the render annotation that configures the
// Docker network for function containers.
const annotationRuntimeDockerNetwork = "render.crossplane.io/runtime-docker-network"

// applyDockerNetworkAnnotation sets the Docker network annotation on functions
// if the CROSSPLANE_DIFF_DOCKER_NETWORK environment variable is set.
func applyDockerNetworkAnnotation(fns []pkgv1.Function, log logging.Logger) {
network := os.Getenv(EnvDockerNetwork)
if network == "" {
return
}

log.Debug("Setting Docker network annotation on functions", "network", network)

for i := range fns {
if fns[i].Annotations == nil {
fns[i].Annotations = make(map[string]string)
}

fns[i].Annotations[annotationRuntimeDockerNetwork] = network
}
}

// DefaultFunctionProvider fetches functions from the cluster on each call.
// This is appropriate for the xr command where each XR is processed independently.
type DefaultFunctionProvider struct {
Expand All @@ -74,6 +104,8 @@ func (p *DefaultFunctionProvider) GetFunctionsForComposition(comp *apiextensions

p.logger.Debug("Fetched functions from pipeline", "composition", comp.GetName(), "count", len(fns))

applyDockerNetworkAnnotation(fns, p.logger)

return fns, nil
}

Expand Down Expand Up @@ -168,6 +200,8 @@ func (p *CachedFunctionProvider) GetFunctionsForComposition(comp *apiextensionsv
// Cache for future calls
p.cache[compName] = fns

applyDockerNetworkAnnotation(fns, p.logger)

return fns, nil
Comment on lines 200 to 205
}

Expand Down
68 changes: 68 additions & 0 deletions cmd/diff/diffprocessor/function_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package diffprocessor

import (
"os"
"strings"
"testing"

Expand Down Expand Up @@ -671,3 +672,70 @@ func TestGenerateContainerName(t *testing.T) {
})
}
}

func TestApplyDockerNetworkAnnotation(t *testing.T) {
tests := map[string]struct {
envValue string
fns []pkgv1.Function
wantNetwork string
}{
"EnvSet": {
envValue: "github_network_abc123",
fns: []pkgv1.Function{
{ObjectMeta: metav1.ObjectMeta{Name: "function-1"}},
{ObjectMeta: metav1.ObjectMeta{Name: "function-2"}},
},
wantNetwork: "github_network_abc123",
},
"EnvNotSet": {
envValue: "",
fns: []pkgv1.Function{
{ObjectMeta: metav1.ObjectMeta{Name: "function-1"}},
},
wantNetwork: "",
},
"ExistingAnnotations": {
envValue: "my-network",
fns: []pkgv1.Function{
{
ObjectMeta: metav1.ObjectMeta{
Name: "function-1",
Annotations: map[string]string{
"existing-key": "existing-value",
},
},
},
},
wantNetwork: "my-network",
},
}

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
if tt.envValue != "" {
t.Setenv(EnvDockerNetwork, tt.envValue)
} else {
os.Unsetenv(EnvDockerNetwork)
}
Comment on lines +715 to +719
Comment on lines +715 to +719

logger := tu.TestLogger(t, false)
applyDockerNetworkAnnotation(tt.fns, logger)

for _, fn := range tt.fns {
got := fn.Annotations[annotationRuntimeDockerNetwork]
if got != tt.wantNetwork {
t.Errorf("function %q: network annotation = %q, want %q", fn.Name, got, tt.wantNetwork)
}
}

// Verify existing annotations are preserved when env is set
if tt.wantNetwork != "" {
for _, fn := range tt.fns {
if v, ok := fn.Annotations["existing-key"]; ok && v != "existing-value" {
t.Errorf("existing annotation was modified: got %q, want %q", v, "existing-value")
}
}
}
Comment on lines +731 to +738
})
}
}
Loading