Skip to content

Commit

Permalink
Enable tridentctl to show a list of its required container images
Browse files Browse the repository at this point in the history
  • Loading branch information
benpresnell authored Mar 17, 2021
1 parent 63d6433 commit 04f92e0
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
###############################################################################

bin/trident*
trident-required-images.md
coverage/**
vendor/
operator/trident-operator
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ trident_build:
@${GO_LINUX} ${BUILD} -ldflags $(BUILD_FLAGS) -o ${TRIDENT_VOLUME_PATH}/bin/${CLI_BIN} ${CLI_PKG}
@${GO_LINUX} ${BUILD} -ldflags $(BUILD_FLAGS) -o ${TRIDENT_VOLUME_PATH}/bin/chwrap chwrap/chwrap.go
cp ${BIN_DIR}/${BIN} ${BIN_DIR}/${CLI_BIN} .
${BIN_DIR}/${CLI_BIN} images -o markdown > trident-required-images.md
chwrap/make-tarball.sh ${BIN_DIR}/chwrap chwrap.tar
docker build --build-arg PORT=${PORT} --build-arg BIN=${BIN} --build-arg CLI_BIN=${CLI_BIN} --build-arg K8S=${K8S} -t ${TRIDENT_TAG} --rm .
ifdef REGISTRY_ADDR
Expand Down
187 changes: 187 additions & 0 deletions cli/cmd/images.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright 2021 NetApp, Inc. All Rights Reserved.

package cmd

import (
"errors"
"fmt"
"os"
"regexp"
"strings"

"github.com/olekukonko/tablewriter"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"

k8sclient "github.com/netapp/trident/cli/k8s_client"
tridentconfig "github.com/netapp/trident/config"
"github.com/netapp/trident/utils"
)

var K8sVersion string
var versionNotSupported = "The provided Kubernetes version is not supported: "
var versionNotSemantic = "The provided Kubernetes version was not given in semantic versioning: "

type ImageSet struct {
Images []string `json:"images"`
K8sVersion string `json:"k8sVersion"`
}

type ImageList struct {
ImageSets []ImageSet `json:"imageSets"`
}

func init() {
getImageCmd.Flags().StringVarP(&K8sVersion, "k8s-version", "v", "all",
"Semantic version of Kubernetes cluster")
RootCmd.AddCommand(getImageCmd)
}

var getImageCmd = &cobra.Command{
Use: "images",
Short: "Print a table of the container images Trident needs",
Aliases: []string{},
RunE: func(cmd *cobra.Command, args []string) error {
if OperatingMode == ModeTunnel {
command := []string{"images"}
TunnelCommand(append(command, args...))
return nil
} else {
return printImages()
}
},
}

func printImages() error {
err := listImages()
if err != nil {
if err.Error() == versionNotSupported {
log.Fatal(fmt.Sprintln(versionNotSupported, K8sVersion))
} else {
log.Fatal(fmt.Sprintln(versionNotSemantic, K8sVersion))
}
}

return nil
}

func listImages() error {
var err error
var semVersion *utils.Version
k8sVersions := make([]string, 0)
imageMap := make(map[string][]string)
var installYaml string
var yamlErr error

if K8sVersion == "all" {
minMinorVersion := utils.MustParseSemantic(tridentconfig.KubernetesVersionMin).MinorVersion()
maxMinorVersion := utils.MustParseSemantic(tridentconfig.KubernetesVersionMax).MinorVersion()
for i := minMinorVersion; i <= maxMinorVersion; i++ {
semVersion := fmt.Sprintf("v1.%d.0", i)
k8sVersions = append(k8sVersions, semVersion)
installYaml, yamlErr = getInstallYaml(utils.MustParseSemantic(semVersion))
if yamlErr != nil {
return yamlErr
}
imageMap[semVersion] = getImageNames(installYaml)
}
} else {
semVersion, err = utils.ParseSemantic(K8sVersion)
if err != nil {
return err
}
k8sVersions = append(k8sVersions, K8sVersion)
installYaml, yamlErr = getInstallYaml(semVersion)
if yamlErr != nil {
return yamlErr
}
imageMap[K8sVersion] = getImageNames(installYaml)
}
writeImages(k8sVersions, imageMap)
return nil
}

func getInstallYaml(semVersion *utils.Version) (string, error) {
var yaml string
minorVersion := semVersion.ToMajorMinorVersion().MinorVersion()
isSupportedVersion := minorVersion <= utils.MustParseSemantic(tridentconfig.KubernetesVersionMax).MinorVersion() &&
minorVersion >= utils.MustParseSemantic(tridentconfig.KubernetesVersionMin).MinorVersion()

if isSupportedVersion {
if semVersion.LessThan(utils.MustParseSemantic(tridentconfig.KubernetesCSIVersionMinForced)) {
csi = false
} else {
csi = true
}
} else {
return "", errors.New(fmt.Sprintln(K8sVersion, "The provided Kubernetes version is not supported"))
}

// Get Deployment and Daemonset YAML and collect the names of the container images Trident needs to run.
if csi {
yaml = k8sclient.GetCSIDeploymentYAML(getDeploymentName(true),
tridentconfig.BuildImage, tridentconfig.DefaultAutosupportImage, "", "",
"", "", "", "", []string{}, nil,
nil, false, false, true, semVersion, false)
// trident image here is an empty string because we are already going to get it from the deployment yaml
yaml += k8sclient.GetCSIDaemonSetYAML("", "", "", "",
"", []string{}, nil, nil, false, false, semVersion)
} else {
yaml = k8sclient.GetDeploymentYAML("", tridentconfig.BuildImage, "", []string{}, nil,
nil, false)
}
return yaml, nil
}

func getImageNames(yaml string) []string {
var images []string
lines := strings.Split(yaml, "\n")
// don't get images that are empty strings
imageRegex := regexp.MustCompile(`\s*image:\s*(.*)`)
for i := 0; i < len(lines); i++ {
imageLine := lines[i]
image := strings.TrimSpace(imageRegex.ReplaceAllString(imageLine, "$1"))
if matches := imageRegex.MatchString(imageLine); matches {
// strip out " image:" prefix
if image != "" {
images = append(images, image)
}
}
}
return images
}

func writeImages(k8sVersions []string, imageMap map[string][]string) {

var imageSets []ImageSet
for _, k8sVersion := range k8sVersions {
var images []string
for _, image := range imageMap[k8sVersion] {
images = append(images, image)
}
imageSets = append(imageSets, ImageSet{Images: images, K8sVersion: k8sVersion})
}
switch OutputFormat {
case FormatJSON:
WriteJSON(ImageList{ImageSets: imageSets})
case FormatYAML:
WriteYAML(ImageList{ImageSets: imageSets})
default:
writeImageTable(k8sVersions, imageMap)
}
}

func writeImageTable(k8sVersions []string, imageMap map[string][]string) {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Kubernetes Version", "Container Image"})
if OutputFormat == FormatMarkdown {
// print in markdown table format
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
}
table.SetRowLine(true)
for _, k8sVersion := range k8sVersions {
table.Append([]string{k8sVersion, strings.Join(imageMap[k8sVersion], "\n")})
}
table.Render()
}
29 changes: 29 additions & 0 deletions cli/cmd/images_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 NetApp, Inc. All Rights Reserved.
*/

package cmd

import (
"testing"

log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)

func TestImages(t *testing.T) {
log.Debug("Running TestImages...")

unsupportedVersion := "1.9.0"
invalidVersion := "1.10.12.2240"
supportedVersion := "1.17.0"

K8sVersion = unsupportedVersion
assert.Error(t, listImages(), "Unsupported version %s should return an error.", K8sVersion)

K8sVersion = invalidVersion
assert.Error(t, listImages(), "Invalid version %s should return an error.", K8sVersion)

K8sVersion = supportedVersion
assert.NoError(t, listImages(), "Supported version %s should not return an error.", K8sVersion)
}
1 change: 1 addition & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
FormatName = "name"
FormatWide = "wide"
FormatYAML = "yaml"
FormatMarkdown = "markdown"

ModeDirect = "direct"
ModeTunnel = "tunnel"
Expand Down
59 changes: 59 additions & 0 deletions docs/Required-Container-Images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
| KUBERNETES VERSION | CONTAINER IMAGE |
|--------------------|---------------------------------------------------------|
| v1.11.0 | netapp/trident:21.04.0-custom |
|--------------------|---------------------------------------------------------|
| v1.12.0 | netapp/trident:21.04.0-custom |
|--------------------|---------------------------------------------------------|
| v1.13.0 | netapp/trident:21.04.0-custom |
|--------------------|---------------------------------------------------------|
| v1.14.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | quay.io/k8scsi/csi-provisioner:v1.6.1 |
| | quay.io/k8scsi/csi-attacher:v2.2.1 |
| | quay.io/k8scsi/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|
| v1.15.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | quay.io/k8scsi/csi-provisioner:v1.6.1 |
| | quay.io/k8scsi/csi-attacher:v2.2.1 |
| | quay.io/k8scsi/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|
| v1.16.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | quay.io/k8scsi/csi-provisioner:v1.6.1 |
| | quay.io/k8scsi/csi-attacher:v2.2.1 |
| | quay.io/k8scsi/csi-resizer:v1.1.0 |
| | quay.io/k8scsi/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|
| v1.17.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | k8s.gcr.io/sig-storage/csi-provisioner:v2.1.0 |
| | k8s.gcr.io/sig-storage/csi-attacher:v3.1.0 |
| | k8s.gcr.io/sig-storage/csi-resizer:v1.1.0 |
| | k8s.gcr.io/sig-storage/csi-snapshotter:v3.0.3 |
| | k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|
| v1.18.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | k8s.gcr.io/sig-storage/csi-provisioner:v2.1.0 |
| | k8s.gcr.io/sig-storage/csi-attacher:v3.1.0 |
| | k8s.gcr.io/sig-storage/csi-resizer:v1.1.0 |
| | k8s.gcr.io/sig-storage/csi-snapshotter:v3.0.3 |
| | k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|
| v1.19.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | k8s.gcr.io/sig-storage/csi-provisioner:v2.1.0 |
| | k8s.gcr.io/sig-storage/csi-attacher:v3.1.0 |
| | k8s.gcr.io/sig-storage/csi-resizer:v1.1.0 |
| | k8s.gcr.io/sig-storage/csi-snapshotter:v3.0.3 |
| | k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|
| v1.20.0 | netapp/trident:21.04.0-custom |
| | netapp/trident-autosupport:21.01 |
| | k8s.gcr.io/sig-storage/csi-provisioner:v2.1.0 |
| | k8s.gcr.io/sig-storage/csi-attacher:v3.1.0 |
| | k8s.gcr.io/sig-storage/csi-resizer:v1.1.0 |
| | k8s.gcr.io/sig-storage/csi-snapshotter:v3.0.3 |
| | k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.1.0 |
|--------------------|---------------------------------------------------------|

0 comments on commit 04f92e0

Please sign in to comment.