Skip to content

Commit

Permalink
fix: fix hgctl in high kubenetes version problem by auto detecting k8…
Browse files Browse the repository at this point in the history
…s version and adding helm lookup function
  • Loading branch information
2456868764 committed Nov 8, 2023
1 parent 26654ae commit a3fcd02
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 17 deletions.
27 changes: 25 additions & 2 deletions pkg/cmd/hgctl/helm/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"helm.sh/helm/v3/pkg/engine"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/repo"
"k8s.io/client-go/rest"
"sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -134,6 +135,12 @@ type RendererOptions struct {
// fields for RemoteRenderer
Version string
RepoURL string

// Capabilities
Capabilities *chartutil.Capabilities

// rest config
restConfig *rest.Config
}

type RendererOption func(*RendererOptions)
Expand Down Expand Up @@ -174,6 +181,18 @@ func WithRepoURL(repo string) RendererOption {
}
}

func WithCapabilities(capabilities *chartutil.Capabilities) RendererOption {
return func(opts *RendererOptions) {
opts.Capabilities = capabilities
}
}

func WithRestConfig(config *rest.Config) RendererOption {
return func(opts *RendererOptions) {
opts.restConfig = config
}
}

// LocalFileRenderer load yaml files from local file system
type LocalFileRenderer struct {
Opts *RendererOptions
Expand Down Expand Up @@ -419,7 +438,11 @@ func renderManifest(valsYaml string, cht *chart.Chart, builtIn bool, opts *Rende
Namespace: opts.Namespace,
}
// TODO need to specify k8s version
caps := chartutil.DefaultCapabilities
var caps *chartutil.Capabilities
caps = opts.Capabilities
if caps == nil {
caps = chartutil.DefaultCapabilities
}
// maybe we need a configuration to change this caps
resVals, err := chartutil.ToRenderValues(cht, valsMap, RelOpts, caps)
if err != nil {
Expand All @@ -428,7 +451,7 @@ func renderManifest(valsYaml string, cht *chart.Chart, builtIn bool, opts *Rende
if builtIn {
resVals["Values"].(chartutil.Values)["enabled"] = true
}
filesMap, err := engine.Render(cht, resVals)
filesMap, err := engine.RenderWithClient(cht, resVals, opts.restConfig)
if err != nil {
return "", fmt.Errorf("Render chart failed err: %s", err)
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/cmd/hgctl/installer/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package installer
import (
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
"helm.sh/helm/v3/pkg/chartutil"
"sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -49,6 +50,8 @@ type ComponentOptions struct {
ChartName string
Version string
Quiet bool
// Capabilities
Capabilities *chartutil.Capabilities
}

type ComponentOption func(*ComponentOptions)
Expand Down Expand Up @@ -83,6 +86,12 @@ func WithComponentVersion(version string) ComponentOption {
}
}

func WithComponentCapabilities(capabilities *chartutil.Capabilities) ComponentOption {
return func(opts *ComponentOptions) {
opts.Capabilities = capabilities
}
}

func WithQuiet() ComponentOption {
return func(opts *ComponentOptions) {
opts.Quiet = true
Expand Down
7 changes: 6 additions & 1 deletion pkg/cmd/hgctl/installer/gateway_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"strings"

"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
"github.com/alibaba/higress/pkg/cmd/hgctl/manifests"
)

Expand All @@ -34,9 +35,10 @@ type GatewayAPIComponent struct {
opts *ComponentOptions
renderer helm.Renderer
writer io.Writer
kubeCli kubernetes.CLIClient
}

func NewGatewayAPIComponent(profile *helm.Profile, writer io.Writer, opts ...ComponentOption) (Component, error) {
func NewGatewayAPIComponent(kubeCli kubernetes.CLIClient, profile *helm.Profile, writer io.Writer, opts ...ComponentOption) (Component, error) {
newOpts := &ComponentOptions{}
for _, opt := range opts {
opt(newOpts)
Expand All @@ -55,6 +57,8 @@ func NewGatewayAPIComponent(profile *helm.Profile, writer io.Writer, opts ...Com
helm.WithVersion(newOpts.Version),
helm.WithFS(manifests.BuiltinOrDir("")),
helm.WithDir(chartDir),
helm.WithCapabilities(newOpts.Capabilities),
helm.WithRestConfig(kubeCli.RESTConfig()),
)
if err != nil {
return nil, err
Expand All @@ -65,6 +69,7 @@ func NewGatewayAPIComponent(profile *helm.Profile, writer io.Writer, opts ...Com
renderer: renderer,
opts: newOpts,
writer: writer,
kubeCli: kubeCli,
}
return gatewayAPIComponent, nil
}
Expand Down
10 changes: 8 additions & 2 deletions pkg/cmd/hgctl/installer/higress.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ package installer
import (
"errors"
"fmt"
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
"io"

"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
)

const (
Expand All @@ -31,6 +33,7 @@ type HigressComponent struct {
opts *ComponentOptions
renderer helm.Renderer
writer io.Writer
kubeCli kubernetes.CLIClient
}

func (h *HigressComponent) ComponentName() ComponentName {
Expand Down Expand Up @@ -89,7 +92,7 @@ func (h *HigressComponent) RenderManifest() (string, error) {
return manifest, nil
}

func NewHigressComponent(profile *helm.Profile, writer io.Writer, opts ...ComponentOption) (Component, error) {
func NewHigressComponent(kubeCli kubernetes.CLIClient, profile *helm.Profile, writer io.Writer, opts ...ComponentOption) (Component, error) {
newOpts := &ComponentOptions{}
for _, opt := range opts {
opt(newOpts)
Expand All @@ -105,6 +108,8 @@ func NewHigressComponent(profile *helm.Profile, writer io.Writer, opts ...Compon
helm.WithNamespace(newOpts.Namespace),
helm.WithRepoURL(newOpts.RepoURL),
helm.WithVersion(newOpts.Version),
helm.WithCapabilities(newOpts.Capabilities),
helm.WithRestConfig(kubeCli.RESTConfig()),
)
if err != nil {
return nil, err
Expand All @@ -115,6 +120,7 @@ func NewHigressComponent(profile *helm.Profile, writer io.Writer, opts ...Compon
renderer: renderer,
opts: newOpts,
writer: writer,
kubeCli: kubeCli,
}
return higressComponent, nil
}
31 changes: 28 additions & 3 deletions pkg/cmd/hgctl/installer/installer_k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"

"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
"github.com/alibaba/higress/pkg/cmd/hgctl/helm/object"
Expand Down Expand Up @@ -202,6 +203,19 @@ func (o *K8sInstaller) DeleteManifests(manifestMap map[ComponentName]string) err
return nil
}

// WriteManifests write component manifests to local files
func (o *K8sInstaller) WriteManifests(manifestMap map[ComponentName]string) error {
if o.kubeCli == nil {
return errors.New("no injected k8s cli into K8sInstaller")
}
rootPath, _ := os.Getwd()
for name, manifest := range manifestMap {
fileName := filepath.Join(rootPath, string(name)+".yaml")
util.WriteFileString(fileName, manifest, 0o644)
}
return nil
}

// deleteManifest delete manifest to certain namespace
func (o *K8sInstaller) deleteManifest(manifest string, ns string) error {
objs, err := object.ParseK8sObjectsFromYAMLManifest(manifest)
Expand Down Expand Up @@ -239,6 +253,14 @@ func NewK8sInstaller(profile *helm.Profile, cli kubernetes.CLIClient, writer io.
if profile == nil {
return nil, errors.New("install profile is empty")
}
// initialize server info
serverInfo, _ := NewServerInfo(cli)
fmt.Fprintf(writer, "\n⌛️ Detecting kubernetes version ... ")
capabilities, err := serverInfo.GetCapabilities()
if err != nil {
return nil, err
}
fmt.Fprintf(writer, "%s\n", capabilities.KubeVersion.Version)
// initialize components
components := make(map[ComponentName]Component)
opts := []ComponentOption{
Expand All @@ -247,11 +269,12 @@ func NewK8sInstaller(profile *helm.Profile, cli kubernetes.CLIClient, writer io.
WithComponentVersion(profile.Charts.Higress.Version),
WithComponentRepoURL(profile.Charts.Higress.Url),
WithComponentChartName(profile.Charts.Higress.Name),
WithComponentCapabilities(capabilities),
}
if quiet {
opts = append(opts, WithQuiet())
}
higressComponent, err := NewHigressComponent(profile, writer, opts...)
higressComponent, err := NewHigressComponent(cli, profile, writer, opts...)
if err != nil {
return nil, fmt.Errorf("NewHigressComponent failed, err: %s", err)
}
Expand All @@ -267,12 +290,13 @@ func NewK8sInstaller(profile *helm.Profile, cli kubernetes.CLIClient, writer io.
WithComponentVersion("1.18.2"),
WithComponentRepoURL("embed://istiobase"),
WithComponentChartName("istio"),
WithComponentCapabilities(capabilities),
}
if quiet {
opts = append(opts, WithQuiet())
}

istioCRDComponent, err := NewIstioCRDComponent(profile, writer, opts...)
istioCRDComponent, err := NewIstioCRDComponent(cli, profile, writer, opts...)
if err != nil {
return nil, fmt.Errorf("NewIstioCRDComponent failed, err: %s", err)
}
Expand All @@ -285,12 +309,13 @@ func NewK8sInstaller(profile *helm.Profile, cli kubernetes.CLIClient, writer io.
WithComponentVersion("1.0.0"),
WithComponentRepoURL("embed://gatewayapi"),
WithComponentChartName("gatewayAPI"),
WithComponentCapabilities(capabilities),
}
if quiet {
opts = append(opts, WithQuiet())
}

gatewayAPIComponent, err := NewGatewayAPIComponent(profile, writer, opts...)
gatewayAPIComponent, err := NewGatewayAPIComponent(cli, profile, writer, opts...)
if err != nil {
return nil, fmt.Errorf("NewGatewayAPIComponent failed, err: %s", err)
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/cmd/hgctl/installer/istio.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"strings"

"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
"github.com/alibaba/higress/pkg/cmd/hgctl/manifests"
)

Expand All @@ -33,9 +34,10 @@ type IstioCRDComponent struct {
opts *ComponentOptions
renderer helm.Renderer
writer io.Writer
kubeCli kubernetes.CLIClient
}

func NewIstioCRDComponent(profile *helm.Profile, writer io.Writer, opts ...ComponentOption) (Component, error) {
func NewIstioCRDComponent(kubeCli kubernetes.CLIClient, profile *helm.Profile, writer io.Writer, opts ...ComponentOption) (Component, error) {
newOpts := &ComponentOptions{}
for _, opt := range opts {
opt(newOpts)
Expand All @@ -54,6 +56,8 @@ func NewIstioCRDComponent(profile *helm.Profile, writer io.Writer, opts ...Compo
helm.WithVersion(newOpts.Version),
helm.WithFS(manifests.BuiltinOrDir("")),
helm.WithDir(chartDir),
helm.WithCapabilities(newOpts.Capabilities),
helm.WithRestConfig(kubeCli.RESTConfig()),
)
if err != nil {
return nil, err
Expand All @@ -64,6 +68,8 @@ func NewIstioCRDComponent(profile *helm.Profile, writer io.Writer, opts ...Compo
helm.WithNamespace(newOpts.Namespace),
helm.WithRepoURL(newOpts.RepoURL),
helm.WithVersion(newOpts.Version),
helm.WithCapabilities(newOpts.Capabilities),
helm.WithRestConfig(kubeCli.RESTConfig()),
)
if err != nil {
return nil, err
Expand All @@ -75,6 +81,7 @@ func NewIstioCRDComponent(profile *helm.Profile, writer io.Writer, opts ...Compo
renderer: renderer,
opts: newOpts,
writer: writer,
kubeCli: kubeCli,
}
return istioComponent, nil
}
Expand Down
66 changes: 66 additions & 0 deletions pkg/cmd/hgctl/installer/server_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// 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.

package installer

import (
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
"github.com/pkg/errors"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chartutil"
"k8s.io/client-go/discovery"
)

type ServerInfo struct {
kubeCli kubernetes.CLIClient
}

func (c *ServerInfo) GetCapabilities() (*chartutil.Capabilities, error) {
// force a discovery cache invalidation to always fetch the latest server version/capabilities.
dc := c.kubeCli.KubernetesInterface().Discovery()

kubeVersion, err := dc.ServerVersion()
if err != nil {
return nil, errors.Wrap(err, "could not get server version from Kubernetes")
}
// Issue #6361:
// Client-Go emits an error when an API service is registered but unimplemented.
// We trap that error here and print a warning. But since the discovery client continues
// building the API object, it is correctly populated with all valid APIs.
// See https://github.com/kubernetes/kubernetes/issues/72051#issuecomment-521157642
apiVersions, err := action.GetVersionSet(dc)
if err != nil {
if discovery.IsGroupDiscoveryFailedError(err) {
} else {
return nil, errors.Wrap(err, "could not get apiVersions from Kubernetes")
}
}
capabilities := &chartutil.Capabilities{
APIVersions: apiVersions,
KubeVersion: chartutil.KubeVersion{
Version: kubeVersion.GitVersion,
Major: kubeVersion.Major,
Minor: kubeVersion.Minor,
},
HelmVersion: chartutil.DefaultCapabilities.HelmVersion,
}
return capabilities, nil
}

func NewServerInfo(kubCli kubernetes.CLIClient) (*ServerInfo, error) {
serverInfo := &ServerInfo{
kubeCli: kubCli,
}
return serverInfo, nil
}
8 changes: 8 additions & 0 deletions pkg/cmd/hgctl/kubernetes/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type CLIClient interface {

// CreateNamespace create namespace
CreateNamespace(namespace string) error

// KubernetesInterface get kubernetes interface
KubernetesInterface() kubernetes.Interface
}

var _ CLIClient = &client{}
Expand Down Expand Up @@ -246,3 +249,8 @@ func (c *client) CreateNamespace(namespace string) error {

return nil
}

// KubernetesInterface get kubernetes interface
func (c *client) KubernetesInterface() kubernetes.Interface {
return c.kube
}
Loading

0 comments on commit a3fcd02

Please sign in to comment.