mirror of
https://github.com/alibaba/higress.git
synced 2026-04-22 04:27:26 +08:00
feat: store profile to configmap or home dir and merge profiles to select when upgrade and uninstall (#649)
This commit is contained in:
@@ -70,6 +70,7 @@ func (h *HigressComponent) Run() error {
|
||||
if err := h.renderer.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.profile.HigressVersion = h.opts.Version
|
||||
h.started = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@ package installer
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
)
|
||||
|
||||
type DockerInstaller struct {
|
||||
started bool
|
||||
standalone *StandaloneComponent
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
started bool
|
||||
standalone *StandaloneComponent
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
profileStore ProfileStore
|
||||
}
|
||||
|
||||
func (d *DockerInstaller) Install() error {
|
||||
@@ -37,11 +37,11 @@ func (d *DockerInstaller) Install() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
fmt.Fprintf(d.writer, "\n✔️ Wrote Profile: \"%s\" \n", profileName)
|
||||
if err := util.WriteFileString(profileName, util.ToYAML(d.profile), 0o644); err != nil {
|
||||
return err
|
||||
profileName, err1 := d.profileStore.Save(d.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(d.writer, "\n✔️ Wrote Profile: \"%s\" \n", profileName)
|
||||
|
||||
fmt.Fprintf(d.writer, "\n🎊 Install All Resources Complete!\n")
|
||||
return nil
|
||||
@@ -55,9 +55,11 @@ func (d *DockerInstaller) UnInstall() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
profileName, err1 := d.profileStore.Delete(d.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(d.writer, "\n✔️ Removed Profile: \"%s\" \n", profileName)
|
||||
os.Remove(profileName)
|
||||
|
||||
fmt.Fprintf(d.writer, "\n🎊 Uninstall All Resources Complete!\n")
|
||||
return nil
|
||||
@@ -92,10 +94,19 @@ func NewDockerInstaller(profile *helm.Profile, writer io.Writer, quiet bool) (*D
|
||||
return nil, fmt.Errorf("NewStandaloneComponent failed, err: %s", err)
|
||||
}
|
||||
|
||||
profileInstalledPath, err1 := GetProfileInstalledPath()
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
profileStore, err2 := NewFileDirProfileStore(profileInstalledPath)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
op := &DockerInstaller{
|
||||
profile: profile,
|
||||
standalone: standaloneComponent,
|
||||
writer: writer,
|
||||
profile: profile,
|
||||
standalone: standaloneComponent,
|
||||
writer: writer,
|
||||
profileStore: profileStore,
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm/object"
|
||||
@@ -28,11 +29,12 @@ import (
|
||||
)
|
||||
|
||||
type K8sInstaller struct {
|
||||
started bool
|
||||
components map[ComponentName]Component
|
||||
kubeCli kubernetes.CLIClient
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
started bool
|
||||
components map[ComponentName]Component
|
||||
kubeCli kubernetes.CLIClient
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
profileStore ProfileStore
|
||||
}
|
||||
|
||||
func (o *K8sInstaller) Install() error {
|
||||
@@ -44,10 +46,6 @@ func (o *K8sInstaller) Install() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := GetProfileInstalledPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := o.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -62,11 +60,16 @@ func (o *K8sInstaller) Install() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
fmt.Fprintf(o.writer, "\n✔️ Wrote Profile: \"%s\" \n", profileName)
|
||||
if err := util.WriteFileString(profileName, util.ToYAML(o.profile), 0o644); err != nil {
|
||||
return err
|
||||
profileName, err1 := o.profileStore.Save(o.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(o.writer, "\n✔️ Wrote Profile in kubernetes configmap: \"%s\" \n", profileName)
|
||||
fmt.Fprintf(o.writer, "\n Use bellow kubectl command to edit profile for upgrade. \n")
|
||||
fmt.Fprintf(o.writer, " ================================================================================== \n")
|
||||
names := strings.Split(profileName, "/")
|
||||
fmt.Fprintf(o.writer, " kubectl edit configmap %s -n %s \n", names[1], names[0])
|
||||
fmt.Fprintf(o.writer, " ================================================================================== \n")
|
||||
|
||||
fmt.Fprintf(o.writer, "\n🎊 Install All Resources Complete!\n")
|
||||
|
||||
@@ -92,9 +95,11 @@ func (o *K8sInstaller) UnInstall() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
profileName, err1 := o.profileStore.Delete(o.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(o.writer, "\n✔️ Removed Profile: \"%s\" \n", profileName)
|
||||
os.Remove(profileName)
|
||||
|
||||
fmt.Fprintf(o.writer, "\n🎊 Uninstall All Resources Complete!\n")
|
||||
|
||||
@@ -322,11 +327,17 @@ func NewK8sInstaller(profile *helm.Profile, cli kubernetes.CLIClient, writer io.
|
||||
components[GatewayAPI] = gatewayAPIComponent
|
||||
}
|
||||
|
||||
profileStore, err := NewConfigmapProfileStore(cli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
op := &K8sInstaller{
|
||||
profile: profile,
|
||||
components: components,
|
||||
kubeCli: cli,
|
||||
writer: writer,
|
||||
profile: profile,
|
||||
components: components,
|
||||
kubeCli: cli,
|
||||
writer: writer,
|
||||
profileStore: profileStore,
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
247
pkg/cmd/hgctl/installer/profile_store.go
Normal file
247
pkg/cmd/hgctl/installer/profile_store.go
Normal file
@@ -0,0 +1,247 @@
|
||||
// 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
ProfileConfigmapKey = "profile"
|
||||
ProfileConfigmapName = "higress-profile"
|
||||
ProfileConfigmapAnnotation = "higress.io/install"
|
||||
ProfileFilePrefix = "install"
|
||||
)
|
||||
|
||||
type ProfileContext struct {
|
||||
Profile *helm.Profile
|
||||
SourceType string
|
||||
Namespace string
|
||||
PathOrName string
|
||||
Install helm.InstallMode
|
||||
HigressVersion string
|
||||
}
|
||||
|
||||
type ProfileStore interface {
|
||||
Save(profile *helm.Profile) (string, error)
|
||||
List() ([]*ProfileContext, error)
|
||||
Delete(profile *helm.Profile) (string, error)
|
||||
}
|
||||
|
||||
type FileDirProfileStore struct {
|
||||
profilesPath string
|
||||
}
|
||||
|
||||
func (f *FileDirProfileStore) Save(profile *helm.Profile) (string, error) {
|
||||
namespace := profile.Global.Namespace
|
||||
install := profile.Global.Install
|
||||
var profileName = ""
|
||||
if install == helm.InstallK8s || install == helm.InstallLocalK8s {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, namespace))
|
||||
} else {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, install))
|
||||
}
|
||||
if err := util.WriteFileString(profileName, util.ToYAML(profile), 0o644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return profileName, nil
|
||||
}
|
||||
|
||||
func (f *FileDirProfileStore) List() ([]*ProfileContext, error) {
|
||||
profileContexts := make([]*ProfileContext, 0)
|
||||
dir, err := os.ReadDir(f.profilesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range dir {
|
||||
if !strings.HasSuffix(file.Name(), ".yaml") {
|
||||
continue
|
||||
}
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
fileName := filepath.Join(f.profilesPath, file.Name())
|
||||
content, err2 := os.ReadFile(fileName)
|
||||
if err2 != nil {
|
||||
continue
|
||||
}
|
||||
profile, err3 := helm.UnmarshalProfile(string(content))
|
||||
if err3 != nil {
|
||||
continue
|
||||
}
|
||||
profileContext := &ProfileContext{
|
||||
Profile: profile,
|
||||
Namespace: profile.Global.Namespace,
|
||||
Install: profile.Global.Install,
|
||||
HigressVersion: profile.HigressVersion,
|
||||
SourceType: "file",
|
||||
PathOrName: fileName,
|
||||
}
|
||||
profileContexts = append(profileContexts, profileContext)
|
||||
}
|
||||
return profileContexts, nil
|
||||
}
|
||||
|
||||
func (f *FileDirProfileStore) Delete(profile *helm.Profile) (string, error) {
|
||||
namespace := profile.Global.Namespace
|
||||
install := profile.Global.Install
|
||||
var profileName = ""
|
||||
if install == helm.InstallK8s || install == helm.InstallLocalK8s {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, namespace))
|
||||
} else {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, install))
|
||||
}
|
||||
if err := os.Remove(profileName); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return profileName, nil
|
||||
}
|
||||
|
||||
func NewFileDirProfileStore(profilesPath string) (ProfileStore, error) {
|
||||
if _, err := os.Stat(profilesPath); os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(profilesPath, os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
profileStore := &FileDirProfileStore{
|
||||
profilesPath: profilesPath,
|
||||
}
|
||||
return profileStore, nil
|
||||
}
|
||||
|
||||
type ConfigmapProfileStore struct {
|
||||
kubeCli kubernetes.CLIClient
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) Save(profile *helm.Profile) (string, error) {
|
||||
bytes, err := json.Marshal(profile)
|
||||
jsonProfile := ""
|
||||
if err == nil {
|
||||
jsonProfile = string(bytes)
|
||||
}
|
||||
annotation := make(map[string]string, 0)
|
||||
annotation[ProfileConfigmapAnnotation] = jsonProfile
|
||||
configmap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: profile.Global.Namespace,
|
||||
Name: ProfileConfigmapName,
|
||||
Annotations: annotation,
|
||||
},
|
||||
}
|
||||
configmap.Data = make(map[string]string, 0)
|
||||
configmap.Data[ProfileConfigmapKey] = util.ToYAML(profile)
|
||||
name := fmt.Sprintf("%s/%s", profile.Global.Namespace, ProfileConfigmapName)
|
||||
if err := c.applyConfigmap(configmap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) List() ([]*ProfileContext, error) {
|
||||
profileContexts := make([]*ProfileContext, 0)
|
||||
configmapList, err := c.listConfigmaps(ProfileConfigmapName, "", 100)
|
||||
if err != nil {
|
||||
return profileContexts, err
|
||||
}
|
||||
for _, configmap := range configmapList.Items {
|
||||
if data, ok := configmap.Data[ProfileConfigmapKey]; ok {
|
||||
profile, err := helm.UnmarshalProfile(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
profileContext := &ProfileContext{
|
||||
Profile: profile,
|
||||
Namespace: profile.Global.Namespace,
|
||||
Install: profile.Global.Install,
|
||||
HigressVersion: profile.HigressVersion,
|
||||
SourceType: "configmap",
|
||||
PathOrName: fmt.Sprintf("%s/%s", profile.Global.Namespace, configmap.Name),
|
||||
}
|
||||
profileContexts = append(profileContexts, profileContext)
|
||||
}
|
||||
}
|
||||
return profileContexts, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) Delete(profile *helm.Profile) (string, error) {
|
||||
configmap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: profile.Global.Namespace,
|
||||
Name: ProfileConfigmapName,
|
||||
},
|
||||
}
|
||||
name := fmt.Sprintf("%s/%s", profile.Global.Namespace, ProfileConfigmapName)
|
||||
if err := c.deleteConfigmap(configmap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) listConfigmaps(name string, namespace string, size int64) (*corev1.ConfigMapList, error) {
|
||||
var result *corev1.ConfigMapList
|
||||
var err error
|
||||
if len(namespace) == 0 {
|
||||
result, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps("").List(context.Background(), metav1.ListOptions{Limit: size, FieldSelector: fmt.Sprintf("metadata.name=%s", name)})
|
||||
} else {
|
||||
result, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(namespace).List(context.Background(), metav1.ListOptions{Limit: size, FieldSelector: fmt.Sprintf("metadata.name=%s", name)})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) applyConfigmap(configmap *corev1.ConfigMap) error {
|
||||
_, err := c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Get(context.Background(), configmap.Name, metav1.GetOptions{})
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
_, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Create(context.Background(), configmap, metav1.CreateOptions{})
|
||||
return err
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Update(context.Background(), configmap, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) deleteConfigmap(configmap *corev1.ConfigMap) error {
|
||||
err := c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Delete(context.Background(), configmap.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewConfigmapProfileStore(kubeCli kubernetes.CLIClient) (ProfileStore, error) {
|
||||
profileStore := &ConfigmapProfileStore{
|
||||
kubeCli: kubeCli,
|
||||
}
|
||||
return profileStore, nil
|
||||
}
|
||||
@@ -58,7 +58,10 @@ func (s *StandaloneComponent) Install() error {
|
||||
if err := s.agent.Install(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set Higress version
|
||||
if version, err := s.agent.Version(); err == nil {
|
||||
s.profile.HigressVersion = version
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,7 +89,10 @@ func (s *StandaloneComponent) Upgrade() error {
|
||||
if err := s.agent.Upgrade(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set Higress version
|
||||
if version, err := s.agent.Version(); err != nil {
|
||||
s.profile.HigressVersion = version
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -112,10 +118,6 @@ func NewStandaloneComponent(profile *helm.Profile, writer io.Writer, opts ...Com
|
||||
}
|
||||
|
||||
func prepareProfile(profile *helm.Profile) error {
|
||||
if _, err := GetProfileInstalledPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(profile.InstallPackagePath) == 0 {
|
||||
dir, err := GetDefaultInstallPackagePath()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user