Skip to content

Commit 5ba17fd

Browse files
authored
refactor: mirror-resources (#2975)
Signed-off-by: Philip Laine <[email protected]>
1 parent 3c8dcb8 commit 5ba17fd

20 files changed

+810
-43
lines changed

.gitattributes

-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
# Set this repository to use unix style line endings
21
* text eol=lf
3-
*.png -text
4-
*.gif -text
5-
*.jpg -text

site/src/content/docs/commands/zarf_package_mirror-resources.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ zarf package mirror-resources [ PACKAGE_SOURCE ] [flags]
2525
2626
# Mirror resources to internal Zarf resources
2727
$ zarf package mirror-resources <your-package.tar.zst> \
28-
--registry-url 127.0.0.1:31999 \
28+
--registry-url http://zarf-docker-registry.zarf.svc.cluster.local:5000 \
2929
--registry-push-username zarf-push \
3030
--registry-push-password <generated-registry-push-password> \
3131
--git-url http://zarf-gitea-http.zarf.svc.cluster.local:3000 \
@@ -57,6 +57,7 @@ $ zarf package mirror-resources <your-package.tar.zst> \
5757
--registry-push-username string Username to access to the registry Zarf is configured to use (default "zarf-push")
5858
--registry-url string External registry url address to use for this Zarf cluster
5959
--retries int Number of retries to perform for Zarf deploy operations like git/image pushes or Helm installs (default 3)
60+
--shasum string Shasum of the package to pull. Required if pulling a https package. A shasum can be retrieved using 'zarf dev sha256sum <url>'
6061
--skip-signature-validation Skip validating the signature of the Zarf package
6162
```
6263

src/cmd/package.go

+47-16
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,27 @@ import (
1111
"os"
1212
"path/filepath"
1313
"regexp"
14+
"runtime"
1415
"strings"
1516

17+
"github.com/AlecAivazis/survey/v2"
18+
"github.com/defenseunicorns/pkg/helpers/v2"
19+
"github.com/spf13/cobra"
20+
"github.com/spf13/viper"
21+
"oras.land/oras-go/v2/registry"
22+
1623
"github.com/zarf-dev/zarf/src/cmd/common"
24+
"github.com/zarf-dev/zarf/src/config"
1725
"github.com/zarf-dev/zarf/src/config/lang"
26+
"github.com/zarf-dev/zarf/src/internal/dns"
1827
"github.com/zarf-dev/zarf/src/internal/packager2"
28+
"github.com/zarf-dev/zarf/src/pkg/cluster"
1929
"github.com/zarf-dev/zarf/src/pkg/lint"
2030
"github.com/zarf-dev/zarf/src/pkg/message"
31+
"github.com/zarf-dev/zarf/src/pkg/packager"
2132
"github.com/zarf-dev/zarf/src/pkg/packager/filters"
2233
"github.com/zarf-dev/zarf/src/pkg/packager/sources"
2334
"github.com/zarf-dev/zarf/src/types"
24-
25-
"oras.land/oras-go/v2/registry"
26-
27-
"github.com/AlecAivazis/survey/v2"
28-
"github.com/defenseunicorns/pkg/helpers/v2"
29-
"github.com/spf13/cobra"
30-
"github.com/spf13/viper"
31-
"github.com/zarf-dev/zarf/src/config"
32-
"github.com/zarf-dev/zarf/src/pkg/cluster"
33-
"github.com/zarf-dev/zarf/src/pkg/packager"
3435
)
3536

3637
var packageCmd = &cobra.Command{
@@ -128,18 +129,47 @@ var packageMirrorCmd = &cobra.Command{
128129
}
129130
},
130131
RunE: func(cmd *cobra.Command, args []string) error {
131-
packageSource, err := choosePackage(args)
132+
var c *cluster.Cluster
133+
if dns.IsServiceURL(pkgConfig.InitOpts.RegistryInfo.Address) || dns.IsServiceURL(pkgConfig.InitOpts.GitServer.Address) {
134+
var err error
135+
c, err = cluster.NewCluster()
136+
if err != nil {
137+
return err
138+
}
139+
}
140+
src, err := choosePackage(args)
132141
if err != nil {
133142
return err
134143
}
135-
pkgConfig.PkgOpts.PackageSource = packageSource
136-
pkgClient, err := packager.New(&pkgConfig)
144+
filter := filters.Combine(
145+
filters.ByLocalOS(runtime.GOOS),
146+
filters.BySelectState(pkgConfig.PkgOpts.OptionalComponents),
147+
)
148+
149+
loadOpt := packager2.LoadOptions{
150+
Source: src,
151+
Shasum: pkgConfig.PkgOpts.Shasum,
152+
PublicKeyPath: pkgConfig.PkgOpts.PublicKeyPath,
153+
SkipSignatureValidation: pkgConfig.PkgOpts.SkipSignatureValidation,
154+
Filter: filter,
155+
}
156+
pkgPaths, err := packager2.LoadPackage(cmd.Context(), loadOpt)
137157
if err != nil {
138158
return err
139159
}
140-
defer pkgClient.ClearTempPaths()
141-
if err := pkgClient.Mirror(cmd.Context()); err != nil {
142-
return fmt.Errorf("failed to mirror package: %w", err)
160+
defer os.RemoveAll(pkgPaths.Base)
161+
mirrorOpt := packager2.MirrorOptions{
162+
Cluster: c,
163+
PackagePaths: *pkgPaths,
164+
Filter: filter,
165+
RegistryInfo: pkgConfig.InitOpts.RegistryInfo,
166+
GitInfo: pkgConfig.InitOpts.GitServer,
167+
NoImageChecksum: pkgConfig.MirrorOpts.NoImgChecksum,
168+
Retries: pkgConfig.PkgOpts.Retries,
169+
}
170+
err = packager2.Mirror(cmd.Context(), mirrorOpt)
171+
if err != nil {
172+
return err
143173
}
144174
return nil
145175
},
@@ -482,6 +512,7 @@ func bindMirrorFlags(v *viper.Viper) {
482512
// Always require confirm flag (no viper)
483513
mirrorFlags.BoolVar(&config.CommonOptions.Confirm, "confirm", false, lang.CmdPackageDeployFlagConfirm)
484514

515+
mirrorFlags.StringVar(&pkgConfig.PkgOpts.Shasum, "shasum", "", lang.CmdPackagePullFlagShasum)
485516
mirrorFlags.BoolVar(&pkgConfig.MirrorOpts.NoImgChecksum, "no-img-checksum", false, lang.CmdPackageMirrorFlagNoChecksum)
486517
mirrorFlags.BoolVar(&pkgConfig.PkgOpts.SkipSignatureValidation, "skip-signature-validation", false, lang.CmdPackageFlagSkipSignatureValidation)
487518

src/config/lang/english.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ $ zarf init --artifact-push-password={PASSWORD} --artifact-push-username={USERNA
233233
CmdPackageMirrorExample = `
234234
# Mirror resources to internal Zarf resources
235235
$ zarf package mirror-resources <your-package.tar.zst> \
236-
--registry-url 127.0.0.1:31999 \
236+
--registry-url http://zarf-docker-registry.zarf.svc.cluster.local:5000 \
237237
--registry-push-username zarf-push \
238238
--registry-push-password <generated-registry-push-password> \
239239
--git-url http://zarf-gitea-http.zarf.svc.cluster.local:3000 \

src/internal/dns/dns.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors
3+
4+
// Package dns contains DNS related functionality.
5+
package dns
6+
7+
import (
8+
"errors"
9+
"fmt"
10+
"net/url"
11+
"regexp"
12+
"strconv"
13+
)
14+
15+
var (
16+
// localClusterServiceRegex is used to match the local cluster service format:
17+
localClusterServiceRegex = regexp.MustCompile(`^(?P<name>[^\.]+)\.(?P<namespace>[^\.]+)\.svc\.cluster\.local$`)
18+
)
19+
20+
// IsServiceURL returns true if the give url complies with the service url format.
21+
func IsServiceURL(serviceURL string) bool {
22+
_, _, _, err := ParseServiceURL(serviceURL)
23+
return err == nil
24+
}
25+
26+
// ParseServiceURL takes a serviceURL and parses it to find the service info for connecting to the cluster. The string is expected to follow the following format:
27+
// Example serviceURL: http://{SERVICE_NAME}.{NAMESPACE}.svc.cluster.local:{PORT}.
28+
func ParseServiceURL(serviceURL string) (string, string, int, error) {
29+
if serviceURL == "" {
30+
return "", "", 0, errors.New("service url cannot be empty")
31+
}
32+
parsedURL, err := url.Parse(serviceURL)
33+
if err != nil {
34+
return "", "", 0, err
35+
}
36+
if parsedURL.Port() == "" {
37+
return "", "", 0, errors.New("service url does not have a port")
38+
}
39+
remotePort, err := strconv.Atoi(parsedURL.Port())
40+
if err != nil {
41+
return "", "", 0, err
42+
}
43+
matches := localClusterServiceRegex.FindStringSubmatch(parsedURL.Hostname())
44+
if len(matches) != 3 {
45+
return "", "", 0, fmt.Errorf("invalid service url %s", serviceURL)
46+
}
47+
return matches[2], matches[1], remotePort, nil
48+
}

src/internal/dns/dns_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors
3+
4+
package dns
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestServiceURL(t *testing.T) {
13+
t.Parallel()
14+
15+
tests := []struct {
16+
name string
17+
serviceURL string
18+
expectedErr string
19+
expectedNamespace string
20+
expectedName string
21+
expectedPort int
22+
}{
23+
{
24+
name: "correct service url",
25+
serviceURL: "http://foo.bar.svc.cluster.local:5000",
26+
expectedNamespace: "bar",
27+
expectedName: "foo",
28+
expectedPort: 5000,
29+
},
30+
{
31+
name: "invalid service url without port",
32+
serviceURL: "http://google.com",
33+
expectedErr: "service url does not have a port",
34+
},
35+
{
36+
name: "invalid service url with port",
37+
serviceURL: "http://google.com:3000",
38+
expectedErr: "invalid service url http://google.com:3000",
39+
},
40+
{
41+
name: "empty service url",
42+
serviceURL: "",
43+
expectedErr: "service url cannot be empty",
44+
},
45+
}
46+
for _, tt := range tests {
47+
t.Run(tt.name, func(t *testing.T) {
48+
t.Parallel()
49+
50+
isServiceURL := IsServiceURL(tt.serviceURL)
51+
namespace, name, port, err := ParseServiceURL(tt.serviceURL)
52+
if tt.expectedErr != "" {
53+
require.False(t, isServiceURL)
54+
require.EqualError(t, err, tt.expectedErr)
55+
return
56+
}
57+
require.True(t, isServiceURL)
58+
require.Equal(t, tt.expectedNamespace, namespace)
59+
require.Equal(t, tt.expectedName, name)
60+
require.Equal(t, tt.expectedPort, port)
61+
})
62+
}
63+
}

0 commit comments

Comments
 (0)