Skip to content

Commit 345cdf0

Browse files
committed
feat(bundle): introduce bundle archive format, implement copy command to convert archive to registry and vice versa
* `werf bundle copy` command: * `--repo` param has been deprecated in favor of new `--from=ADDR` param * `--tag` param has been deprecated in favor of new `--from=ADDR` param * `--to-tag` param has been deprecated in favor of `--to=ADDR` param new format * New `--from=ADDR` and `--to=ADDR` params accept addr in different formats: * `archive:PATH_TO_ARCHIVE.tar.gz` — bundle archive * `docker://registry.example.com/group/project` — remote bundle in container registry * without explicitly specified schema address parsed also as a remote bundle in container registry * Bundle archive has following structure: * `chart.tar.gz` — regular helm chart archive * `images/TAG.tar.gz` — dir contains all werf images referenced from chart values `.Values.werf.image.NAME`, named by tags Refs werf/3p-helm#216 Signed-off-by: Timofey Kirillov <timofey.kirillov@flant.com>
1 parent 3a7c68d commit 345cdf0

File tree

12 files changed

+895
-87
lines changed

12 files changed

+895
-87
lines changed

cmd/werf/bundle/copy/copy.go

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@ import (
88
"github.com/spf13/cobra"
99
helm_v3 "helm.sh/helm/v3/cmd/helm"
1010

11+
"github.com/werf/logboek"
1112
"github.com/werf/werf/cmd/werf/common"
1213
"github.com/werf/werf/pkg/deploy/bundles"
14+
"github.com/werf/werf/pkg/docker_registry"
1315
"github.com/werf/werf/pkg/werf"
1416
"github.com/werf/werf/pkg/werf/global_warnings"
1517
)
1618

1719
var cmdData struct {
18-
Repo *common.RepoData
20+
// TODO(2.0): Legacy {
21+
Repo string
1922
Tag string
20-
To *common.RepoData
2123
ToTag string
24+
// TODO(2.0): } Legacy
25+
26+
From string
27+
To string
2228
}
2329

2430
var commonCmdData common.CmdData
@@ -57,22 +63,16 @@ func NewCmd(ctx context.Context) *cobra.Command {
5763
common.SetupInsecureHelmDependencies(&commonCmdData, cmd)
5864
common.SetupSkipTlsVerifyRegistry(&commonCmdData, cmd)
5965

60-
cmdData.Repo = common.NewRepoData("repo", common.RepoDataOptions{OnlyAddress: true})
61-
cmdData.Repo.SetupCmd(cmd)
62-
63-
cmdData.To = common.NewRepoData("to", common.RepoDataOptions{OnlyAddress: true})
64-
cmdData.To.SetupCmd(cmd)
65-
6666
common.SetupLogOptions(&commonCmdData, cmd)
6767
common.SetupLogProjectDir(&commonCmdData, cmd)
6868
common.SetupPlatform(&commonCmdData, cmd)
6969

70-
defaultTag := os.Getenv("WERF_TAG")
71-
if defaultTag == "" {
72-
defaultTag = "latest"
73-
}
74-
cmd.Flags().StringVarP(&cmdData.Tag, "tag", "", defaultTag, "Provide from tag version of the bundle to copy ($WERF_TAG or latest by default)")
75-
cmd.Flags().StringVarP(&cmdData.ToTag, "to-tag", "", "", "Provide to tag version of the bundle to copy ($WERF_TO_TAG or same as --tag by default)")
70+
cmd.Flags().StringVarP(&cmdData.Repo, "repo", "", os.Getenv("WERF_REPO"), "Deprecated param, use --from=ADDR instead. Source address of bundle which should be copied.")
71+
cmd.Flags().StringVarP(&cmdData.Tag, "tag", "", os.Getenv("WERF_TAG"), "Deprecated param, use --from=REPO:TAG instead. Provide from tag version of the bundle to copy ($WERF_TAG or latest by default).")
72+
cmd.Flags().StringVarP(&cmdData.ToTag, "to-tag", "", os.Getenv("WERF_TO_TAG"), "Deprecated param, use --to=REPO:TAG instead. Provide to tag version of the bundle to copy ($WERF_TO_TAG or same as --tag by default).")
73+
74+
cmd.Flags().StringVarP(&cmdData.From, "from", "", os.Getenv("WERF_FROM"), "Source address of the bundle to copy, specify bundle archive using schema `archive:PATH_TO_ARCHIVE.tar.gz`, specify remote bundle with schema `[docker://]REPO:TAG` or without schema.")
75+
cmd.Flags().StringVarP(&cmdData.To, "to", "", os.Getenv("WERF_TO"), "Destination address of the bundle to copy, specify bundle archive using schema `archive:PATH_TO_ARCHIVE.tar.gz`, specify remote bundle with schema `[docker://]REPO:TAG` or without schema.")
7676

7777
return cmd
7878
}
@@ -93,26 +93,68 @@ func runCopy(ctx context.Context) error {
9393
return err
9494
}
9595

96-
if *cmdData.Repo.Address == "" {
97-
return fmt.Errorf("--repo=ADDRESS param required")
96+
fromAddrRaw := cmdData.From
97+
if fromAddrRaw != "" && cmdData.Repo != "" {
98+
return fmt.Errorf("unable to use --repo=ADDRESS and --from=ADDRESS params at the same time: please specify only --from=ADDRESS param, --repo param has been deprecated")
99+
} else if cmdData.Repo != "" {
100+
logboek.Context(ctx).Warn().LogF("Please use --from=ADDRESS param instead of deprecated --repo=ADDRESS param\n")
101+
fromAddrRaw = cmdData.Repo
102+
}
103+
if fromAddrRaw == "" {
104+
return fmt.Errorf("--from=ADDRESS param required")
98105
}
99-
if *cmdData.To.Address == "" {
106+
107+
toAddrRaw := cmdData.To
108+
if toAddrRaw == "" {
100109
return fmt.Errorf("--to=ADDRESS param required")
101110
}
102111

103-
fromRegistry, err := cmdData.Repo.CreateDockerRegistry(ctx, *commonCmdData.InsecureRegistry, *commonCmdData.SkipTlsVerifyRegistry)
112+
fromAddr, err := bundles.ParseAddr(fromAddrRaw)
104113
if err != nil {
105-
return fmt.Errorf("error creating container registry accessor for repo %s: %w", *cmdData.Repo.Address, err)
114+
return fmt.Errorf("invalid from addr %q: %w", fromAddrRaw, err)
106115
}
107116

108-
fromTag := cmdData.Tag
109-
toTag := cmdData.ToTag
110-
if toTag == "" {
111-
toTag = fromTag
117+
toAddr, err := bundles.ParseAddr(toAddrRaw)
118+
if err != nil {
119+
return fmt.Errorf("invalid to addr %q: %w", toAddrRaw, err)
112120
}
113121

114-
fromRef := fmt.Sprintf("%s:%s", *cmdData.Repo.Address, fromTag)
115-
toRef := fmt.Sprintf("%s:%s", *cmdData.To.Address, toTag)
122+
var fromRegistry, toRegistry docker_registry.Interface
116123

117-
return bundles.Copy(ctx, fromRef, toRef, bundlesRegistryClient, fromRegistry)
124+
if fromAddr.RegistryAddress != nil {
125+
// TODO(2.0): remove legacy compatibility param
126+
if cmdData.Tag != "" {
127+
logboek.Context(ctx).Warn().LogF("Please use --from=REPO:TAG tag specification instead of deprecated --tag=TAG param\n")
128+
fromAddr.RegistryAddress.Tag = cmdData.Tag
129+
}
130+
131+
fromRegistry, err = common.CreateDockerRegistry(fromAddr.RegistryAddress.Repo, *commonCmdData.InsecureRegistry, *commonCmdData.SkipTlsVerifyRegistry)
132+
if err != nil {
133+
return err
134+
}
135+
}
136+
137+
if toAddr.RegistryAddress != nil {
138+
// TODO(2.0): remove legacy compatibility param
139+
if cmdData.ToTag != "" {
140+
logboek.Context(ctx).Warn().LogF("Please use --to=REPO:TAG tag specification instead of deprecated --to-tag=TAG param\n")
141+
toAddr.RegistryAddress.Tag = cmdData.ToTag
142+
}
143+
144+
toRegistry, err = common.CreateDockerRegistry(toAddr.RegistryAddress.Repo, *commonCmdData.InsecureRegistry, *commonCmdData.SkipTlsVerifyRegistry)
145+
if err != nil {
146+
return err
147+
}
148+
}
149+
150+
return logboek.Context(ctx).LogProcess("Copy bundle").DoError(func() error {
151+
logboek.Context(ctx).LogFDetails("From: %s\n", fromAddr.String())
152+
logboek.Context(ctx).LogFDetails("To: %s\n", toAddr.String())
153+
154+
return bundles.Copy(ctx, fromAddr, toAddr, bundles.CopyOptions{
155+
BundlesRegistryClient: bundlesRegistryClient,
156+
FromRegistry: fromRegistry,
157+
ToRegistry: toRegistry,
158+
})
159+
})
118160
}

cmd/werf/common/repo_data.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ import (
1414
"github.com/werf/werf/pkg/storage"
1515
)
1616

17+
func CreateDockerRegistry(addr string, insecureRegistry, skipTlsVerifyRegistry bool) (docker_registry.Interface, error) {
18+
regOpts := docker_registry.DockerRegistryOptions{
19+
InsecureRegistry: insecureRegistry,
20+
SkipTlsVerifyRegistry: skipTlsVerifyRegistry,
21+
}
22+
23+
dockerRegistry, err := docker_registry.NewDockerRegistry(addr, "", regOpts)
24+
if err != nil {
25+
return nil, fmt.Errorf("error creating container registry accessor for repo %q: %w", addr, err)
26+
}
27+
28+
return dockerRegistry, nil
29+
}
30+
1731
func (repoData *RepoData) CreateDockerRegistry(ctx context.Context, insecureRegistry, skipTlsVerifyRegistry bool) (docker_registry.Interface, error) {
1832
addr, err := repoData.GetAddress()
1933
if err != nil {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,6 @@ replace k8s.io/helm => github.com/werf/helm v0.0.0-20210202111118-81e74d46da0f
314314

315315
replace github.com/deislabs/oras => github.com/werf/third-party-oras v0.9.1-0.20210927171747-6d045506f4c8
316316

317-
replace helm.sh/helm/v3 => github.com/werf/3p-helm/v3 v3.0.0-20220823144404-27eb1367786c
317+
replace helm.sh/helm/v3 => github.com/werf/3p-helm/v3 v3.0.0-20220902145201-6265178e3c32
318318

319319
replace github.com/go-git/go-git/v5 => github.com/ZauberNerd/go-git/v5 v5.4.3-0.20220315170230-29ec1bc1e5db

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,8 +2050,8 @@ github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59b
20502050
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
20512051
github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU=
20522052
github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
2053-
github.com/werf/3p-helm/v3 v3.0.0-20220823144404-27eb1367786c h1:/cMYGHrCXCohS+2Thjj+7fiVVG1a/LmGC4BxZOK1sYY=
2054-
github.com/werf/3p-helm/v3 v3.0.0-20220823144404-27eb1367786c/go.mod h1:NxtE2KObf2PrzDl6SIamPFPKyAqWi10iWuvKlQn/Yao=
2053+
github.com/werf/3p-helm/v3 v3.0.0-20220902145201-6265178e3c32 h1:Z3XL0banUFF7IkIzY82onwWA2qiTvuQ0pBMERA/scis=
2054+
github.com/werf/3p-helm/v3 v3.0.0-20220902145201-6265178e3c32/go.mod h1:NxtE2KObf2PrzDl6SIamPFPKyAqWi10iWuvKlQn/Yao=
20552055
github.com/werf/copy-recurse v0.2.4 h1:kEyGUKhgS8WdEOjInNQKgk4lqPWzP2AgR27F3dcGsVc=
20562056
github.com/werf/copy-recurse v0.2.4/go.mod h1:KVHSQ90p19xflWW0B7BJhLBwmSbEtuxIaBnjlUYRPhk=
20572057
github.com/werf/helm v0.0.0-20210202111118-81e74d46da0f h1:81YscYTF9mmTf0ULOsCmm42YWQp+qWDzWi1HjWniZrg=

pkg/deploy/bundles/addr.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package bundles
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/werf/werf/pkg/deploy/bundles/registry"
8+
)
9+
10+
const (
11+
ArchiveSchema = "archive:"
12+
RegistrySchema = "docker://"
13+
)
14+
15+
type Addr struct {
16+
*ArchiveAddress
17+
*RegistryAddress
18+
}
19+
20+
func (addr *Addr) String() string {
21+
if addr.RegistryAddress != nil {
22+
return addr.RegistryAddress.FullName()
23+
}
24+
if addr.ArchiveAddress != nil {
25+
return addr.ArchiveAddress.Path
26+
}
27+
return ""
28+
}
29+
30+
type ArchiveAddress struct {
31+
Path string
32+
}
33+
34+
type RegistryAddress struct {
35+
*registry.Reference
36+
}
37+
38+
func ParseAddr(addr string) (*Addr, error) {
39+
switch {
40+
case strings.HasPrefix(addr, ArchiveSchema):
41+
return &Addr{ArchiveAddress: parseArchiveAddress(addr)}, nil
42+
case strings.HasPrefix(addr, RegistrySchema):
43+
if regAddr, err := parseRegistryAddress(addr); err != nil {
44+
return nil, fmt.Errorf("unable to parse registry address %q: %w", addr, err)
45+
} else {
46+
return &Addr{RegistryAddress: regAddr}, nil
47+
}
48+
default:
49+
if regAddr, err := parseRegistryAddress(addr); err != nil {
50+
return nil, fmt.Errorf("unable to parse registry address %q: %w", addr, err)
51+
} else {
52+
return &Addr{RegistryAddress: regAddr}, nil
53+
}
54+
}
55+
}
56+
57+
func parseRegistryAddress(addr string) (*RegistryAddress, error) {
58+
cleanAddr := strings.TrimPrefix(addr, RegistrySchema)
59+
60+
ref, err := registry.ParseReference(cleanAddr)
61+
if err != nil {
62+
return nil, err
63+
}
64+
65+
if ref.Tag == "" {
66+
ref.Tag = "latest"
67+
}
68+
69+
return &RegistryAddress{Reference: ref}, nil
70+
}
71+
72+
func parseArchiveAddress(addr string) *ArchiveAddress {
73+
path := strings.TrimPrefix(addr, ArchiveSchema)
74+
return &ArchiveAddress{Path: path}
75+
}

pkg/deploy/bundles/addr_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package bundles
2+
3+
import (
4+
. "github.com/onsi/ginkgo/v2"
5+
. "github.com/onsi/gomega"
6+
)
7+
8+
var _ = Describe("Bundle addr", func() {
9+
It("should parse different bundle address schemas", func() {
10+
{
11+
addr, err := ParseAddr("registry.werf.io/group/image:mytag")
12+
Expect(err).NotTo(HaveOccurred())
13+
Expect(addr.RegistryAddress).NotTo(BeNil())
14+
Expect(addr.ArchiveAddress).To(BeNil())
15+
Expect(addr.Repo).To(Equal("registry.werf.io/group/image"))
16+
Expect(addr.Tag).To(Equal("mytag"))
17+
}
18+
19+
{
20+
addr, err := ParseAddr("registry.werf.io/group/image")
21+
Expect(err).NotTo(HaveOccurred())
22+
Expect(addr.RegistryAddress).NotTo(BeNil())
23+
Expect(addr.ArchiveAddress).To(BeNil())
24+
Expect(addr.Repo).To(Equal("registry.werf.io/group/image"))
25+
Expect(addr.Tag).To(Equal("latest"))
26+
}
27+
28+
{
29+
addr, err := ParseAddr("archive:path/to/file.tar.gz")
30+
Expect(err).NotTo(HaveOccurred())
31+
Expect(addr.RegistryAddress).To(BeNil())
32+
Expect(addr.ArchiveAddress).NotTo(BeNil())
33+
Expect(addr.Path).To(Equal("path/to/file.tar.gz"))
34+
}
35+
36+
{
37+
addr, err := ParseAddr("archive:/absolute/path/to/file.tar.gz")
38+
Expect(err).NotTo(HaveOccurred())
39+
Expect(addr.RegistryAddress).To(BeNil())
40+
Expect(addr.ArchiveAddress).NotTo(BeNil())
41+
Expect(addr.Path).To(Equal("/absolute/path/to/file.tar.gz"))
42+
}
43+
})
44+
})

0 commit comments

Comments
 (0)