github.com/oam-dev/kubevela@v1.9.11/pkg/utils/env/env.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package env 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "os" 24 "path/filepath" 25 26 "github.com/AlecAivazis/survey/v2" 27 "github.com/kubevela/pkg/util/singleton" 28 "github.com/pkg/errors" 29 v1 "k8s.io/api/core/v1" 30 apierrors "k8s.io/apimachinery/pkg/api/errors" 31 "k8s.io/apimachinery/pkg/labels" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 34 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 35 "github.com/oam-dev/kubevela/apis/types" 36 "github.com/oam-dev/kubevela/pkg/oam" 37 "github.com/oam-dev/kubevela/pkg/oam/util" 38 "github.com/oam-dev/kubevela/pkg/utils" 39 "github.com/oam-dev/kubevela/pkg/utils/common" 40 "github.com/oam-dev/kubevela/pkg/utils/system" 41 ) 42 43 const ( 44 // DefaultEnvNamespace is namespace of default env 45 DefaultEnvNamespace = "default" 46 ) 47 48 // following functions are CRUD of env 49 50 // CreateEnv will create e env. 51 // Because Env equals to namespace, one env should not be updated 52 func CreateEnv(envArgs *types.EnvMeta) (err error) { 53 c := singleton.KubeClient.Get() 54 if envArgs.Namespace == "" { 55 err = common.AskToChooseOneNamespace(c, envArgs) 56 if err != nil { 57 return err 58 } 59 } 60 if envArgs.Name == "" { 61 prompt := &survey.Input{ 62 Message: "Please name your new env:", 63 } 64 err = survey.AskOne(prompt, &envArgs.Name) 65 if err != nil { 66 return err 67 } 68 } 69 ctx := context.TODO() 70 71 var nsList v1.NamespaceList 72 err = c.List(ctx, &nsList, client.MatchingLabels{oam.LabelControlPlaneNamespaceUsage: oam.VelaNamespaceUsageEnv, 73 oam.LabelNamespaceOfEnvName: envArgs.Name}) 74 if err != nil { 75 return err 76 } 77 if len(nsList.Items) > 0 { 78 return fmt.Errorf("env name %s already exists", envArgs.Name) 79 } 80 81 namespace, err := utils.GetNamespace(ctx, c, envArgs.Namespace) 82 if err != nil && !apierrors.IsNotFound(err) { 83 return err 84 } 85 if namespace != nil { 86 existedEnv := namespace.GetLabels()[oam.LabelNamespaceOfEnvName] 87 if existedEnv != "" && existedEnv != envArgs.Name { 88 return fmt.Errorf("the namespace %s was already assigned to env %s", envArgs.Namespace, existedEnv) 89 } 90 } 91 err = utils.CreateOrUpdateNamespace(ctx, c, envArgs.Namespace, utils.MergeOverrideLabels(map[string]string{ 92 oam.LabelControlPlaneNamespaceUsage: oam.VelaNamespaceUsageEnv, 93 }), utils.MergeNoConflictLabels(map[string]string{ 94 oam.LabelNamespaceOfEnvName: envArgs.Name, 95 })) 96 if err != nil { 97 return err 98 } 99 return nil 100 101 } 102 103 // GetEnvByName will get env info by name 104 func GetEnvByName(name string) (*types.EnvMeta, error) { 105 if name == DefaultEnvNamespace { 106 return &types.EnvMeta{Name: DefaultEnvNamespace, Namespace: DefaultEnvNamespace}, nil 107 } 108 namespace, err := getEnvNamespaceByName(name) 109 if err != nil { 110 return nil, err 111 } 112 return &types.EnvMeta{ 113 Name: name, 114 Namespace: namespace.Name, 115 }, nil 116 } 117 118 // ListEnvs will list all envs 119 // if envName specified, return list that only contains one env 120 func ListEnvs(envName string) ([]*types.EnvMeta, error) { 121 var envList []*types.EnvMeta 122 if envName != "" { 123 env, err := GetEnvByName(envName) 124 if err != nil { 125 if os.IsNotExist(err) { 126 err = fmt.Errorf("env %s not exist", envName) 127 } 128 return envList, err 129 } 130 envList = append(envList, env) 131 return envList, err 132 } 133 clt := singleton.KubeClient.Get() 134 135 ctx := context.Background() 136 var nsList v1.NamespaceList 137 err := clt.List(ctx, &nsList, client.MatchingLabels{oam.LabelControlPlaneNamespaceUsage: oam.VelaNamespaceUsageEnv}) 138 if err != nil { 139 return nil, err 140 } 141 for _, it := range nsList.Items { 142 envList = append(envList, &types.EnvMeta{ 143 Name: it.Labels[oam.LabelNamespaceOfEnvName], 144 Namespace: it.Name, 145 }) 146 } 147 if len(envList) < 1 { 148 return envList, nil 149 } 150 cur, err := GetCurrentEnv() 151 if err != nil { 152 _ = SetCurrentEnv(envList[0]) 153 envList[0].Current = "*" 154 // we set a current env if not exist 155 // nolint:nilerr 156 return envList, nil 157 } 158 for i := range envList { 159 if envList[i].Name == cur.Name { 160 envList[i].Current = "*" 161 } 162 } 163 return envList, nil 164 } 165 166 // DeleteEnv will delete env and its application 167 func DeleteEnv(envName string) (string, error) { 168 var message string 169 var err error 170 envMeta, err := GetEnvByName(envName) 171 if err != nil { 172 return "", err 173 } 174 clt := singleton.KubeClient.Get() 175 var appList v1beta1.ApplicationList 176 err = clt.List(context.TODO(), &appList, client.InNamespace(envMeta.Namespace)) 177 if err != nil { 178 return "", err 179 } 180 if len(appList.Items) > 0 { 181 err = fmt.Errorf("you can't delete this environment(namespace=%s) that has %d application inside", envMeta.Namespace, len(appList.Items)) 182 return message, err 183 } 184 // reset the labels 185 err = utils.UpdateNamespace(context.TODO(), clt, envMeta.Namespace, utils.MergeOverrideLabels(map[string]string{ 186 oam.LabelNamespaceOfEnvName: "", 187 oam.LabelControlPlaneNamespaceUsage: "", 188 })) 189 if err != nil { 190 return "", err 191 } 192 message = "env " + envName + " deleted" 193 return message, err 194 } 195 196 // GetCurrentEnv will get current env 197 func GetCurrentEnv() (*types.EnvMeta, error) { 198 currentEnvPath, err := system.GetCurrentEnvPath() 199 if err != nil { 200 return nil, err 201 } 202 data, err := os.ReadFile(filepath.Clean(currentEnvPath)) 203 if err != nil { 204 return nil, err 205 } 206 var envMeta types.EnvMeta 207 err = json.Unmarshal(data, &envMeta) 208 if err != nil { 209 em, err := GetEnvByName(string(data)) 210 if err != nil { 211 return nil, err 212 } 213 _ = SetCurrentEnv(em) 214 return em, nil 215 } 216 return &envMeta, nil 217 } 218 219 // SetCurrentEnv will set the current env to the specified one 220 func SetCurrentEnv(meta *types.EnvMeta) error { 221 currentEnvPath, err := system.GetCurrentEnvPath() 222 if err != nil { 223 return err 224 } 225 data, err := json.Marshal(meta) 226 if err != nil { 227 return err 228 } 229 //nolint:gosec 230 if err = os.WriteFile(currentEnvPath, data, 0644); err != nil { 231 return err 232 } 233 return nil 234 } 235 236 // getEnvNamespaceByName get v1.Namespace object by env name 237 func getEnvNamespaceByName(name string) (*v1.Namespace, error) { 238 ctx := context.Background() 239 var nsList v1.NamespaceList 240 err := singleton.KubeClient.Get().List(ctx, &nsList, client.MatchingLabels{oam.LabelNamespaceOfEnvName: name}) 241 if err != nil { 242 return nil, err 243 } 244 if len(nsList.Items) < 1 { 245 return nil, errors.Errorf("Env %s not exist", name) 246 } 247 248 return &nsList.Items[0], nil 249 } 250 251 // SetEnvLabels set labels for namespace 252 func SetEnvLabels(envArgs *types.EnvMeta) error { 253 namespace, err := getEnvNamespaceByName(envArgs.Name) 254 if err != nil { 255 return err 256 } 257 labelsMap, err := labels.ConvertSelectorToLabelsMap(envArgs.Labels) 258 if err != nil { 259 return err 260 } 261 262 namespace.Labels = util.MergeMapOverrideWithDst(namespace.GetLabels(), labelsMap) 263 264 err = singleton.KubeClient.Get().Update(context.Background(), namespace) 265 if err != nil { 266 return errors.Wrapf(err, "fail to set env labelsMap") 267 } 268 return nil 269 }