Skip to content

Commit cc22fa9

Browse files
author
ZhiHanZ
authored
getistio fetch: add name flag in fetch (#26)
* add name flag in fetch * fix UT * convert flag * fix UT * refactor Signed-off-by: zhihanz <zhihan@tetrate.io> * minor changes * refactor * nit * add old tests
1 parent ddc6cb8 commit cc22fa9

File tree

5 files changed

+277
-245
lines changed

5 files changed

+277
-245
lines changed

cmd/fetch.go

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,24 @@ package cmd
1616

1717
import (
1818
"fmt"
19+
"strings"
1920

21+
"github.com/Masterminds/semver"
2022
"github.com/spf13/cobra"
2123

24+
"github.com/tetratelabs/getistio/api"
2225
"github.com/tetratelabs/getistio/src/istioctl"
2326
"github.com/tetratelabs/getistio/src/manifest"
2427
"github.com/tetratelabs/getistio/src/util/logger"
2528
)
2629

30+
type fetchFlags struct {
31+
name, version, flavor string
32+
flavorVersion int64
33+
}
34+
2735
func newFetchCmd(homedir string) *cobra.Command {
28-
var (
29-
flagVersion string
30-
flagFlavor string
31-
flagFlavorVersion int
32-
)
36+
var flag fetchFlags
3337

3438
cmd := &cobra.Command{
3539
Use: "fetch",
@@ -47,6 +51,9 @@ $ getistio fetch --version 1.7 --flavor tetrate --flavor-version 0
4751
# Fetch the istioctl of version=1.7.4 flavor=tetrate flavor-version=0
4852
$ getistio fetch --version 1.7.4 --flavor tetrate --flavor-version 0
4953
54+
# Fetch the istioctl of version=1.7.4 flavor=tetrate flavor-version=0 using name
55+
$ getistio fetch --name 1.7.4-tetrate-v0
56+
5057
# Fetch the latest istioctl of version=1.7.4 and flavor=tetratefips
5158
$ getistio fetch --version 1.7.4 --flavor tetratefips
5259
@@ -75,8 +82,12 @@ For more information, please refer to "getistio list --help" command.
7582
if err != nil {
7683
return fmt.Errorf("error fetching manifest: %v", err)
7784
}
85+
d, err := fetchParams(&flag, ms)
86+
if err != nil {
87+
return err
88+
}
7889

79-
d, err := istioctl.Fetch(homedir, flagVersion, flagFlavor, flagFlavorVersion, ms)
90+
err = istioctl.Fetch(homedir, d, ms)
8091
if err != nil {
8192
return err
8293
}
@@ -97,8 +108,90 @@ For more information, please refer to "getistio list --help" command.
97108

98109
flags := cmd.Flags()
99110
flags.SortFlags = false
100-
flags.StringVarP(&flagVersion, "version", "", "", "Version of istioctl e.g. \"--version 1.7.4\"")
101-
flags.StringVarP(&flagFlavor, "flavor", "", "", "Flavor of istioctl, e.g. \"--flavor tetrate\" or --flavor tetratefips\" or --flavor istio\"")
102-
flags.IntVarP(&flagFlavorVersion, "flavor-version", "", -1, "Version of the flavor, e.g. \"--version 1\"")
111+
flags.StringVarP(&flag.name, "name", "", "", "Name of distribution, e.g. 1.9.0-istio-v0")
112+
flags.StringVarP(&flag.version, "version", "", "", "Version of istioctl e.g. \"--version 1.7.4\". When --name flag is set, this will not be used.")
113+
flags.StringVarP(&flag.flavor, "flavor", "", "",
114+
"Flavor of istioctl, e.g. \"--flavor tetrate\" or --flavor tetratefips\" or --flavor istio\". When --name flag is set, this will not be used.")
115+
flags.Int64VarP(&flag.flavorVersion, "flavor-version", "", -1,
116+
"Version of the flavor, e.g. \"--version 1\". When --name flag is set, this will not be used.")
103117
return cmd
104118
}
119+
120+
func fetchParams(flags *fetchFlags,
121+
ms *api.Manifest) (*api.IstioDistribution, error) {
122+
if len(flags.name) != 0 {
123+
d, err := api.IstioDistributionFromString(flags.name)
124+
if err != nil {
125+
return nil, fmt.Errorf("cannot parse given name %s to istio distribution", flags.name)
126+
}
127+
return d, nil
128+
}
129+
if flags.flavor != api.IstioDistributionFlavorTetrate &&
130+
flags.flavor != api.IstioDistributionFlavorTetrateFIPS &&
131+
flags.flavor != api.IstioDistributionFlavorIstio {
132+
flags.flavor = api.IstioDistributionFlavorTetrate
133+
logger.Infof("fallback to the %s flavor since --flavor flag is not given or not supported\n", flags.flavor)
134+
}
135+
if len(flags.version) == 0 {
136+
for _, m := range ms.IstioDistributions {
137+
if m.Flavor == flags.flavor {
138+
return m, nil
139+
}
140+
}
141+
}
142+
143+
ret := &api.IstioDistribution{Version: flags.version, Flavor: flags.flavor, FlavorVersion: flags.flavorVersion}
144+
145+
if strings.Count(flags.version, ".") == 1 {
146+
// In the case where patch version is not given,
147+
// we find the latest patch version
148+
var (
149+
latest *api.IstioDistribution
150+
prev *semver.Version
151+
)
152+
153+
v, err := semver.NewVersion(flags.version)
154+
if err != nil {
155+
return nil, err
156+
}
157+
158+
for _, d := range ms.IstioDistributions {
159+
cur, err := semver.NewVersion(d.Version)
160+
if err != nil {
161+
return nil, err
162+
}
163+
164+
if d.Flavor == ret.Flavor && cur.Minor() == v.Minor() && (prev == nil || cur.GreaterThan(prev)) {
165+
prev = cur
166+
latest = d
167+
}
168+
}
169+
170+
if latest == nil {
171+
return nil, fmt.Errorf("invalid version %s", ret.Version)
172+
}
173+
174+
ret.Version = latest.Version
175+
logger.Infof("fallback to %s which is the latest patch version in the given verion minor %s\n",
176+
ret.Version, flags.version)
177+
}
178+
179+
if ret.FlavorVersion < 0 {
180+
// search the latest flavor version in this flavor
181+
var found bool
182+
for _, m := range ms.IstioDistributions {
183+
if m.Version == ret.Version && m.Flavor == ret.Flavor {
184+
ret.FlavorVersion = m.FlavorVersion
185+
found = true
186+
break
187+
}
188+
}
189+
if !found {
190+
return nil, fmt.Errorf("unsupported version=%s and flavor=%s", ret.Version, ret.Flavor)
191+
}
192+
logger.Infof("fallback to the flavor %d version which is the latest one in %s-%s\n",
193+
ret.FlavorVersion, ret.Version, ret.Flavor)
194+
}
195+
196+
return ret, nil
197+
}

cmd/fetch_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright 2021 Tetrate
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
"fmt"
19+
"testing"
20+
21+
"github.com/stretchr/testify/assert"
22+
23+
"github.com/tetratelabs/getistio/api"
24+
)
25+
26+
func Test_fetchParams(t *testing.T) {
27+
type tc struct {
28+
flag *fetchFlags
29+
mf *api.Manifest
30+
exp *api.IstioDistribution
31+
}
32+
33+
for i, c := range []tc{
34+
{
35+
// no args -> fall back to the latest tetrate flavor
36+
flag: &fetchFlags{flavorVersion: -1},
37+
mf: &api.Manifest{
38+
IstioDistributions: []*api.IstioDistribution{
39+
{Version: "1.7.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
40+
},
41+
},
42+
exp: &api.IstioDistribution{Version: "1.7.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
43+
},
44+
{
45+
// all given
46+
flag: &fetchFlags{version: "1.7.3", flavorVersion: 100, flavor: api.IstioDistributionFlavorTetrate},
47+
exp: &api.IstioDistribution{Version: "1.7.3", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrate},
48+
},
49+
{
50+
// given name
51+
flag: &fetchFlags{name: "1.7.3-tetrate-v100"},
52+
exp: &api.IstioDistribution{Version: "1.7.3", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrate},
53+
},
54+
{
55+
// flavor not given
56+
flag: &fetchFlags{version: "1.7.3", flavorVersion: 100},
57+
exp: &api.IstioDistribution{Version: "1.7.3", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrate},
58+
},
59+
{
60+
// flavorVersion not given -> fall back to the latest flavor version
61+
flag: &fetchFlags{version: "1.7.3", flavor: api.IstioDistributionFlavorTetrateFIPS, flavorVersion: -1},
62+
mf: &api.Manifest{
63+
IstioDistributions: []*api.IstioDistribution{
64+
{Version: "1.7.3", FlavorVersion: 50, Flavor: api.IstioDistributionFlavorTetrateFIPS},
65+
{Version: "1.7.3", FlavorVersion: 10000000, Flavor: api.IstioDistributionFlavorTetrate},
66+
},
67+
},
68+
exp: &api.IstioDistribution{Version: "1.7.3", FlavorVersion: 50, Flavor: api.IstioDistributionFlavorTetrateFIPS},
69+
},
70+
{
71+
// version not given -> choose the latest version given flavor in manifest
72+
flag: &fetchFlags{flavor: api.IstioDistributionFlavorIstio, flavorVersion: 0},
73+
mf: &api.Manifest{
74+
IstioDistributions: []*api.IstioDistribution{
75+
{Version: "1.7.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrateFIPS},
76+
{Version: "1.8.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorIstio},
77+
},
78+
},
79+
exp: &api.IstioDistribution{Version: "1.8.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorIstio},
80+
},
81+
{
82+
// version and flavor version not given -> choose the latest version given flavor in manifest
83+
flag: &fetchFlags{flavor: api.IstioDistributionFlavorIstio, flavorVersion: -1},
84+
mf: &api.Manifest{
85+
IstioDistributions: []*api.IstioDistribution{
86+
{Version: "1.7.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrateFIPS},
87+
{Version: "1.8.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorIstio},
88+
},
89+
},
90+
exp: &api.IstioDistribution{Version: "1.8.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorIstio},
91+
},
92+
{
93+
// flavorVersion not given -> not found error
94+
flag: &fetchFlags{version: "1.7.3", flavor: api.IstioDistributionFlavorTetrateFIPS, flavorVersion: -1},
95+
mf: &api.Manifest{
96+
IstioDistributions: []*api.IstioDistribution{
97+
{Version: "1.7.3", FlavorVersion: 50, Flavor: api.IstioDistributionFlavorTetrate},
98+
},
99+
},
100+
},
101+
{
102+
// flavor, flavorVersion not given -> fall back to the latest tetrate flavor
103+
flag: &fetchFlags{version: "1.7.3", flavorVersion: -1},
104+
mf: &api.Manifest{
105+
IstioDistributions: []*api.IstioDistribution{
106+
{Version: "1.7.3", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrateFIPS},
107+
{Version: "1.7.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
108+
},
109+
},
110+
exp: &api.IstioDistribution{Version: "1.7.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
111+
},
112+
{
113+
// patch version is not given in 'version', so should fallback to the latest patch version in the minor version
114+
flag: &fetchFlags{version: "1.7", flavor: api.IstioDistributionFlavorTetrateFIPS, flavorVersion: -1},
115+
mf: &api.Manifest{
116+
IstioDistributions: []*api.IstioDistribution{
117+
{Version: "1.7.3", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrate},
118+
{Version: "1.7.1", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrateFIPS},
119+
{Version: "1.8.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
120+
},
121+
},
122+
exp: &api.IstioDistribution{Version: "1.7.1", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrateFIPS},
123+
},
124+
{
125+
// patch version is not given in 'version', so should fallback to the latest patch version in the minor version
126+
flag: &fetchFlags{version: "1.7", flavorVersion: 0},
127+
mf: &api.Manifest{
128+
IstioDistributions: []*api.IstioDistribution{
129+
{Version: "1.7.100", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrate},
130+
{Version: "1.7.20", FlavorVersion: 20, Flavor: api.IstioDistributionFlavorTetrate},
131+
{Version: "1.7.1", FlavorVersion: 1, Flavor: api.IstioDistributionFlavorTetrate},
132+
{Version: "1.7.1", FlavorVersion: 100, Flavor: api.IstioDistributionFlavorTetrateFIPS},
133+
{Version: "1.8.3", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
134+
},
135+
},
136+
exp: &api.IstioDistribution{Version: "1.7.100", FlavorVersion: 0, Flavor: api.IstioDistributionFlavorTetrate},
137+
},
138+
} {
139+
t.Run(fmt.Sprintf("%d-th case", i), func(t *testing.T) {
140+
actual, err := fetchParams(c.flag, c.mf)
141+
if c.exp == nil {
142+
assert.Error(t, err)
143+
} else {
144+
assert.NoError(t, err)
145+
assert.Equal(t, c.exp, actual)
146+
}
147+
})
148+
149+
}
150+
}

doc/en/getistio-cli/reference/getistio_fetch/_index.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ $ getistio fetch --version 1.7 --flavor tetrate --flavor-version 0
2424
# Fetch the istioctl of version=1.7.4 flavor=tetrate flavor-version=0
2525
$ getistio fetch --version 1.7.4 --flavor tetrate --flavor-version 0
2626
27+
# Fetch the istioctl of version=1.7.4 flavor=tetrate flavor-version=0 using name
28+
$ getistio fetch --name 1.7.4-tetrate-v0
29+
2730
# Fetch the latest istioctl of version=1.7.4 and flavor=tetratefips
2831
$ getistio fetch --version 1.7.4 --flavor tetratefips
2932
@@ -52,9 +55,10 @@ For more information, please refer to "getistio list --help" command.
5255
#### Options
5356

5457
```
55-
--version string Version of istioctl e.g. "--version 1.7.4"
56-
--flavor string Flavor of istioctl, e.g. "--flavor tetrate" or --flavor tetratefips" or --flavor istio"
57-
--flavor-version int Version of the flavor, e.g. "--version 1" (default -1)
58+
--name string Name of distribution, e.g. 1.9.0-istio-v0
59+
--version string Version of istioctl e.g. "--version 1.7.4". When --name flag is set, this will not be used.
60+
--flavor string Flavor of istioctl, e.g. "--flavor tetrate" or --flavor tetratefips" or --flavor istio". When --name flag is set, this will not be used.
61+
--flavor-version int Version of the flavor, e.g. "--version 1". When --name flag is set, this will not be used. (default -1)
5862
-h, --help help for fetch
5963
```
6064

0 commit comments

Comments
 (0)