Skip to content

Commit

Permalink
WIP: pkg: detect cluster version alongside platform
Browse files Browse the repository at this point in the history
WIP TBD

Signed-off-by: Francesco Romani <[email protected]>
  • Loading branch information
ffromani committed Jul 12, 2022
1 parent b6335be commit 4bc1e9c
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 26 deletions.
55 changes: 48 additions & 7 deletions pkg/commands/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,16 @@ func NewDetectCommand(commonOpts *CommonOptions) *cobra.Command {
Use: "detect",
Short: "detect the cluster platform (kubernetes, openshift...)",
RunE: func(cmd *cobra.Command, args []string) error {
platDetect := detectPlatform(commonOpts.DebugLog, commonOpts.UserPlatform)
platKind := detectPlatform(commonOpts.DebugLog, commonOpts.UserPlatform)
platVer := detectVersion(commonOpts.DebugLog, platKind.Discovered, commonOpts.UserPlatformVersion)
cluster := clusterDetection{
Platform: platKind,
Version: platVer,
}
if opts.jsonOutput {
json.NewEncoder(os.Stdout).Encode(platDetect)
json.NewEncoder(os.Stdout).Encode(cluster)
} else {
fmt.Printf("%s\n", platDetect.Discovered)
fmt.Printf("%s:%s\n", cluster.Platform.Discovered, cluster.Version.Discovered)
}
return nil
},
Expand All @@ -52,14 +57,25 @@ func NewDetectCommand(commonOpts *CommonOptions) *cobra.Command {
return detect
}

type detectionOutput struct {
type platformDetection struct {
AutoDetected platform.Platform `json:"auto_detected"`
UserSupplied platform.Platform `json:"user_supplied"`
Discovered platform.Platform `json:"discovered"`
}

func detectPlatform(debugLog *log.Logger, userSupplied platform.Platform) detectionOutput {
do := detectionOutput{
type versionDetection struct {
AutoDetected platform.Version `json:"auto_detected"`
UserSupplied platform.Version `json:"user_supplied"`
Discovered platform.Version `json:"discovered"`
}

type clusterDetection struct {
Platform platformDetection `json:"platform"`
Version versionDetection `json:"version"`
}

func detectPlatform(debugLog *log.Logger, userSupplied platform.Platform) platformDetection {
do := platformDetection{
AutoDetected: platform.Unknown,
UserSupplied: userSupplied,
Discovered: platform.Unknown,
Expand All @@ -71,7 +87,7 @@ func detectPlatform(debugLog *log.Logger, userSupplied platform.Platform) detect
return do
}

dp, err := detect.Detect()
dp, err := detect.Platform()
if err != nil {
debugLog.Printf("failed to detect the platform: %v", err)
return do
Expand All @@ -82,3 +98,28 @@ func detectPlatform(debugLog *log.Logger, userSupplied platform.Platform) detect
do.Discovered = do.AutoDetected
return do
}

func detectVersion(debugLog *log.Logger, plat platform.Platform, userSupplied platform.Version) versionDetection {
do := versionDetection{
AutoDetected: platform.MissingVersion,
UserSupplied: userSupplied,
Discovered: platform.MissingVersion,
}

if do.UserSupplied != platform.MissingVersion {
debugLog.Printf("user-supplied version: %q", do.UserSupplied)
do.Discovered = do.UserSupplied
return do
}

dv, err := detect.Version(plat)
if err != nil {
debugLog.Printf("failed to detect the version: %v", err)
return do
}

debugLog.Printf("auto-detected version: %q", dv)
do.AutoDetected = dv
do.Discovered = do.AutoDetected
return do
}
39 changes: 27 additions & 12 deletions pkg/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"io/ioutil"
"log"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand All @@ -30,16 +31,18 @@ import (
)

type CommonOptions struct {
Debug bool
UserPlatform platform.Platform
Log *log.Logger
DebugLog *log.Logger
Replicas int
RTEConfigData string
PullIfNotPresent bool
UpdaterType string
rteConfigFile string
plat string
Debug bool
UserPlatform platform.Platform
UserPlatformVersion platform.Version
Log *log.Logger
DebugLog *log.Logger
Replicas int
RTEConfigData string
PullIfNotPresent bool
UpdaterType string
rteConfigFile string
plat string
platVer string
}

func ShowHelp(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -87,7 +90,7 @@ func NewRootCommand(extraCmds ...NewCommandFunc) *cobra.Command {

func InitFlags(flags *pflag.FlagSet, commonOpts *CommonOptions) {
flags.BoolVarP(&commonOpts.Debug, "debug", "D", false, "enable debug log")
flags.StringVarP(&commonOpts.plat, "platform", "P", "", "platform to deploy on")
flags.StringVarP(&commonOpts.plat, "platform", "P", "", "platform kind:version to deploy on (example kubernetes:v1.22)")
flags.IntVarP(&commonOpts.Replicas, "replicas", "R", 1, "set the replica value - where relevant.")
flags.BoolVar(&commonOpts.PullIfNotPresent, "pull-if-not-present", false, "force pull policies to IfNotPresent.")
flags.StringVar(&commonOpts.rteConfigFile, "rte-config-file", "", "inject rte configuration reading from this file.")
Expand All @@ -104,7 +107,19 @@ func PostSetupOptions(commonOpts *CommonOptions) error {
commonOpts.Log = log.New(os.Stdout, "", log.LstdFlags)

// if it is unknown, it's fine
commonOpts.UserPlatform, _ = platform.FromString(commonOpts.plat)
if commonOpts.plat == "" {
commonOpts.UserPlatform = platform.Unknown
commonOpts.UserPlatformVersion = platform.MissingVersion
} else {
fields := strings.FieldsFunc(commonOpts.plat, func(c rune) bool {
return c == ':'
})
if len(fields) != 2 {
return fmt.Errorf("unsupported platform spec: %q", commonOpts.plat)
}
commonOpts.UserPlatform, _ = platform.ParsePlatform(fields[0])
commonOpts.UserPlatformVersion, _ = platform.ParseVersion(fields[1])
}

if commonOpts.rteConfigFile != "" {
data, err := os.ReadFile(commonOpts.rteConfigFile)
Expand Down
37 changes: 36 additions & 1 deletion pkg/deployer/platform/detect/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package detect

import (
"context"
"fmt"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -26,7 +27,7 @@ import (
"github.com/k8stopologyawareschedwg/deployer/pkg/deployer/platform"
)

func Detect() (platform.Platform, error) {
func Platform() (platform.Platform, error) {
ocpCli, err := clientutil.NewOCPClientSet()
if err != nil {
return platform.Unknown, err
Expand All @@ -43,3 +44,37 @@ func Detect() (platform.Platform, error) {
}
return platform.Kubernetes, nil
}

func Version(plat platform.Platform) (platform.Version, error) {
if plat == platform.OpenShift {
return OpenshiftVersion()
}
return KubernetesVersion()
}

func KubernetesVersion() (platform.Version, error) {
cli, err := clientutil.NewDiscoveryClient()
if err != nil {
return "", err
}
ver, err := cli.ServerVersion()
if err != nil {
return "", err
}
return platform.ParseVersion(ver.GitVersion)
}

func OpenshiftVersion() (platform.Version, error) {
ocpCli, err := clientutil.NewOCPClientSet()
if err != nil {
return platform.MissingVersion, err
}
ocpApi, err := ocpCli.ConfigV1.ClusterOperators().Get(context.TODO(), "openshift-apiserver", metav1.GetOptions{})
if err != nil {
return platform.MissingVersion, err
}
if len(ocpApi.Status.Versions) == 0 {
return platform.MissingVersion, fmt.Errorf("unexpected amount of operands: %d", len(ocpApi.Status.Versions))
}
return platform.ParseVersion(ocpApi.Status.Versions[0].Version)
}
2 changes: 1 addition & 1 deletion pkg/deployer/platform/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (p Platform) String() string {
return string(p)
}

func FromString(plat string) (Platform, bool) {
func ParsePlatform(plat string) (Platform, bool) {
plat = strings.ToLower(plat)
switch plat {
case "kubernetes":
Expand Down
51 changes: 51 additions & 0 deletions pkg/deployer/platform/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2021 Red Hat, Inc.
*/

package platform

import goversion "github.com/aquasecurity/go-version/pkg/version"

type Version string

const MissingVersion Version = ""

func ParseVersion(v string) (Version, error) {
_, err := goversion.Parse(v)
if err != nil {
return Version(""), err
}
return Version(v), nil
}

func (v Version) String() string {
return string(v)
}

func (v Version) AtLeastString(other string) (bool, error) {
ref, err := goversion.Parse(other)
if err != nil {
return false, err
}
ser, err := goversion.Parse(v.String())
if err != nil {
return false, err
}
return ser.Compare(ref) >= 0, nil
}

func (v Version) AtLeast(other Version) (bool, error) {
return v.AtLeastString(other.String())
}
13 changes: 12 additions & 1 deletion test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,23 @@ func (vo validationOutput) String() string {
return sb.String()
}

type detectionOutput struct {
type platformDetection struct {
AutoDetected platform.Platform `json:"auto_detected"`
UserSupplied platform.Platform `json:"user_supplied"`
Discovered platform.Platform `json:"discovered"`
}

type versionDetection struct {
AutoDetected platform.Version `json:"auto_detected"`
UserSupplied platform.Version `json:"user_supplied"`
Discovered platform.Version `json:"discovered"`
}

type clusterDetection struct {
Platform platformDetection `json:"platform"`
Version versionDetection `json:"version"`
}

type imageOutput struct {
TopologyUpdater string `json:"topology_updater"`
SchedulerPlugin string `json:"scheduler_plugin"`
Expand Down
13 changes: 9 additions & 4 deletions test/e2e/positive.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"github.com/k8stopologyawareschedwg/deployer/pkg/manifests/rte"
"github.com/k8stopologyawareschedwg/deployer/pkg/manifests/sched"
"github.com/k8stopologyawareschedwg/deployer/pkg/tlog"
"github.com/k8stopologyawareschedwg/deployer/pkg/validator"

e2enodes "github.com/k8stopologyawareschedwg/deployer/test/e2e/utils/nodes"
e2epods "github.com/k8stopologyawareschedwg/deployer/test/e2e/utils/pods"
Expand Down Expand Up @@ -109,7 +110,7 @@ var _ = ginkgo.Describe("[PositiveFlow] Deployer render", func() {
ginkgo.It("it should reflect the overrides in the output", func() {
cmdline := []string{
filepath.Join(binariesPath, "deployer"),
"-P", "kubernetes",
"-P", "kubernetes:v1.24",
"render",
}
fmt.Fprintf(ginkgo.GinkgoWriter, "running: %v\n", cmdline)
Expand Down Expand Up @@ -148,12 +149,16 @@ var _ = ginkgo.Describe("[PositiveFlow] Deployer detection", func() {
out, err := cmd.Output()
gomega.Expect(err).ToNot(gomega.HaveOccurred())

do := detectionOutput{}
do := clusterDetection{}
if err := json.Unmarshal(out, &do); err != nil {
ginkgo.Fail(fmt.Sprintf("Error unmarshalling output %q: %v", out, err))
}
gomega.Expect(do.AutoDetected).To(gomega.Equal(platform.Kubernetes))
gomega.Expect(do.Discovered).To(gomega.Equal(platform.Kubernetes))
gomega.Expect(do.Platform.AutoDetected).To(gomega.Equal(platform.Kubernetes))
gomega.Expect(do.Platform.Discovered).To(gomega.Equal(platform.Kubernetes))

minVer, err := platform.ParseVersion(validator.ExpectedMinKubeVersion)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(do.Version.Discovered.AtLeast(minVer)).To(gomega.BeTrue(), "cluster version mismatch - check validation")
})
})
})
Expand Down

0 comments on commit 4bc1e9c

Please sign in to comment.