|
| 1 | +/* |
| 2 | +Copyright 2023 The Kubebb 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 cmd |
| 18 | + |
| 19 | +import ( |
| 20 | + "context" |
| 21 | + "fmt" |
| 22 | + "strings" |
| 23 | + "sync" |
| 24 | + |
| 25 | + "github.com/ghodss/yaml" |
| 26 | + appsv1 "k8s.io/api/apps/v1" |
| 27 | + corev1 "k8s.io/api/core/v1" |
| 28 | + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 29 | + "k8s.io/apimachinery/pkg/runtime" |
| 30 | + utilruntime "k8s.io/apimachinery/pkg/util/runtime" |
| 31 | + ctrl "sigs.k8s.io/controller-runtime" |
| 32 | + "sigs.k8s.io/controller-runtime/pkg/client" |
| 33 | + |
| 34 | + "github.com/kubebb/core/api/v1alpha1" |
| 35 | +) |
| 36 | + |
| 37 | +var ( |
| 38 | + once sync.Once |
| 39 | + cc client.Client |
| 40 | +) |
| 41 | + |
| 42 | +const ( |
| 43 | + mustAddForClusterComponent = "ingress-nginx.controller.nodeSelector.kubernetes\\.io/hostname" |
| 44 | + clusterComponentName = "cluster-component" |
| 45 | + installTemplate = `apiVersion: core.kubebb.k8s.com.cn/v1alpha1 |
| 46 | +kind: ComponentPlan |
| 47 | +metadata: |
| 48 | + name: cluster-component |
| 49 | + namespace: u4a-system |
| 50 | +spec: |
| 51 | + approved: true |
| 52 | + name: cluster-component |
| 53 | + version: version |
| 54 | + component: |
| 55 | + name: kubebb.cluster-component |
| 56 | + namespace: kubebb-system` |
| 57 | + |
| 58 | + u4aValueYaml = `# Default values for u4a-system. |
| 59 | +# This is a YAML-formatted file. |
| 60 | +# Declare variables to be passed into your templates. |
| 61 | +
|
| 62 | +# You must check and update the value of each variable below |
| 63 | +deploymentConfig: |
| 64 | + # bffServer info |
| 65 | + bffHost: portal.<replaced-ingress-nginx-ip>.nip.io |
| 66 | + clientName: bff-client |
| 67 | + clientId: bff-client |
| 68 | + clientSecret: 61324af0-1234-4f61-b110-ef57013267d6 |
| 69 | + # BFF server info |
| 70 | + # The host Kubernetes cluster with OIDC enabled or use kube-oidc-proxy in front of k8s-apiserver |
| 71 | + # kube-oidc-proxy will be installed by default |
| 72 | + hostK8sApiWithOidc: https://k8s.<replaced-ingress-nginx-ip>.nip.io |
| 73 | + # Enable https for bff server |
| 74 | + bffHttpsEnabled: true |
| 75 | +
|
| 76 | +registryServer: docker.io |
| 77 | +
|
| 78 | +issuerConfig: |
| 79 | + # oidc certificate info |
| 80 | + # if using kube-odic-proxy, should add both oidc and proxy IP address here |
| 81 | + certificate: |
| 82 | + # MUST update this value |
| 83 | + oidcIPs: |
| 84 | + - <replaced-ingress-nginx-ip> |
| 85 | + # MUST update this value |
| 86 | + dnsNames: |
| 87 | + - portal.<replaced-ingress-nginx-ip>.nip.io |
| 88 | + - oidc-server |
| 89 | + - oidc-server.u4a-system |
| 90 | + - oidc-server.u4a-system.svc |
| 91 | + - kube-oidc-proxy |
| 92 | + - kube-oidc-proxy.u4a-system |
| 93 | + - kube-oidc-proxy.u4a-system.svc |
| 94 | + - k8s.<replaced-ingress-nginx-ip>.nip.io |
| 95 | + spec: |
| 96 | + # Use selfSigned or specified CA(such as CA from kubernetes) |
| 97 | + selfSigned: {} |
| 98 | + # ca: |
| 99 | + # secretName: k8s-ca-key-pair |
| 100 | +
|
| 101 | +# The ingress class id of the nginx ingress to expose the services for external access |
| 102 | +ingress: |
| 103 | + name: portal-ingress |
| 104 | +
|
| 105 | +############################################################################################### |
| 106 | +### Below is the configuration for each service, in most cases, you don't need to update them |
| 107 | +### But update as you need if it's required, such as image, connector etc... |
| 108 | +############################################################################################### |
| 109 | +# Optional but the default: Use Kubernetes CRD for user provider - iam provider |
| 110 | +iamProvider: |
| 111 | + enabled: true |
| 112 | + image: kubebb/iam-provider-ce:v0.1.0 |
| 113 | +
|
| 114 | +# Required: Use dex as the odic service |
| 115 | +oidcServer: |
| 116 | + enabled: true |
| 117 | + host: portal.<replaced-ingress-nginx-ip>.nip.io |
| 118 | + cert: |
| 119 | + ipAddresses: |
| 120 | + - <replaced-ingress-nginx-ip> |
| 121 | + dnsNames: |
| 122 | + - portal.<replaced-ingress-nginx-ip>.nip.io |
| 123 | + - oidc-server |
| 124 | + - oidc-server.u4a-system |
| 125 | + - oidc-server.u4a-system.svc |
| 126 | + - kube-oidc-proxy |
| 127 | + - kube-oidc-proxy.u4a-system |
| 128 | + - kube-oidc-proxy.u4a-system.svc |
| 129 | + - k8s.<replaced-ingress-nginx-ip>.nip.io |
| 130 | + image: kubebb/oidc-server-ce:v0.1.0 |
| 131 | + issuer: https://{{ .Values.deploymentConfig.bffHost }}/oidc |
| 132 | + storageType: kubernetes |
| 133 | + webHttps: 0.0.0.0:5556 |
| 134 | + clientId: bff-client |
| 135 | + connectors: |
| 136 | + - type: k8scrd |
| 137 | + name: k8scrd |
| 138 | + id: k8scrd |
| 139 | + config: |
| 140 | + host: https://127.0.0.1:443 |
| 141 | + insecureSkipVerify: true |
| 142 | + staticClients: |
| 143 | + - id: bff-client |
| 144 | + redirectURIs: |
| 145 | + - https://{{ .Values.deploymentConfig.bffHost }}/ |
| 146 | + name: bff-client |
| 147 | + secret: 61324af0-1234-4f61-b110-ef57013267d6 |
| 148 | + # Enable and update the ip if nip.io is NOT accessible in deployed environment |
| 149 | + hostConfig: |
| 150 | + enabled: true |
| 151 | + hostAliases: |
| 152 | + - hostnames: |
| 153 | + - portal.<replaced-ingress-nginx-ip>.nip.io |
| 154 | + ip: <replaced-ingress-nginx-ip> |
| 155 | + # only enable for debug purpose |
| 156 | + debug: false |
| 157 | +
|
| 158 | +# Optional but the default: BFF server for all API endpoints |
| 159 | +bffServer: |
| 160 | + enabled: true |
| 161 | + image: kubebb/bff-server-ce:v0.1.4 |
| 162 | + host: portal.<replaced-ingress-nginx-ip>.nip.io |
| 163 | + connectorId: k8scrd |
| 164 | + clientId: bff-client |
| 165 | + clientSecret: 61324af0-1234-4f61-b110-ef57013267d6 |
| 166 | + # Enable and update the ip if nip.io is NOT accessible in deployed environment |
| 167 | + hostConfig: |
| 168 | + enabled: true |
| 169 | + hostAliases: |
| 170 | + - hostnames: |
| 171 | + - portal.<replaced-ingress-nginx-ip>.nip.io |
| 172 | + ip: <replaced-ingress-nginx-ip> |
| 173 | +
|
| 174 | +# Required: the host Kubernetes cluster with OIDC enabled |
| 175 | +# or use kube-oidc-proxy in front of k8s-apiserver |
| 176 | +k8s: |
| 177 | + hostK8sApiWithOidc: https://k8s.<replaced-ingress-nginx-ip>.nip.io |
| 178 | +
|
| 179 | +# Generate tenant/namespace/user view for query |
| 180 | +# Install if it's host cluster |
| 181 | +resourceView: |
| 182 | + image: kubebb/resource-viewer-ce:v0.1.0 |
| 183 | +
|
| 184 | +addon-component: |
| 185 | + enabled: true |
| 186 | + tenantManagement: |
| 187 | + image: kubebb/capsule-ce:v0.1.2-20221122 |
| 188 | + kubeOidcProxy: |
| 189 | + image: kubebb/kube-oidc-proxy-ce:v0.3.0-20221008 |
| 190 | + issuerUrl: https://portal.<replaced-ingress-nginx-ip>.nip.io/oidc |
| 191 | + clientId: bff-client |
| 192 | + ingress: |
| 193 | + enabled: true |
| 194 | + name: portal-ingress |
| 195 | + host: k8s.<replaced-ingress-nginx-ip>.nip.io |
| 196 | + certificate: |
| 197 | + ipAddresses: |
| 198 | + # MUST update this value to the host ip of kube-oidc-proxy |
| 199 | + - <replaced-ingress-nginx-ip> |
| 200 | + dnsNames: |
| 201 | + - kube-oidc-proxy |
| 202 | + - kube-oidc-proxy.u4a-system |
| 203 | + - kube-oidc-proxy.u4a-system.svc |
| 204 | + hostConfig: |
| 205 | + enabled: true |
| 206 | + hostAliases: |
| 207 | + - hostnames: |
| 208 | + # MUST update this value |
| 209 | + - portal.<replaced-ingress-nginx-ip>.nip.io |
| 210 | + # MUST update this value |
| 211 | + ip: <replaced-ingress-nginx-ip> |
| 212 | +
|
| 213 | +# Optional: Enable it if use LDAP as user provider |
| 214 | +ldapProvider: |
| 215 | + enabled: false |
| 216 | + storageClass: openebs-hostpath |
| 217 | +# ldapImage: 172.22.96.19/u4a_system/openldap:1.5.0 |
| 218 | +# ldapOrg: test |
| 219 | +# ldapDomain: test.com |
| 220 | +# ldapAdminPwd: xxx |
| 221 | +# ldapAdminImage: 172.22.96.19/u4a_system/phpldapadmin:stable |
| 222 | +
|
| 223 | +cluster-component: |
| 224 | + enabled: false` |
| 225 | +) |
| 226 | + |
| 227 | +func init() { |
| 228 | + Enroll(CLUSTERCOMPONENT, CommonInstaller) |
| 229 | + Enroll(U4A, CommonInstaller) |
| 230 | + Enroll(COMPONENTSTORE, CommonInstaller) |
| 231 | +} |
| 232 | + |
| 233 | +func initCli() { |
| 234 | + cfg, err := ctrl.GetConfig() |
| 235 | + if err != nil { |
| 236 | + panic(err) |
| 237 | + } |
| 238 | + |
| 239 | + fmt.Println("init controller runtime client") |
| 240 | + scheme := runtime.NewScheme() |
| 241 | + utilruntime.Must(v1alpha1.AddToScheme(scheme)) |
| 242 | + utilruntime.Must(appsv1.AddToScheme(scheme)) |
| 243 | + utilruntime.Must(corev1.AddToScheme(scheme)) |
| 244 | + cc, err = client.New(cfg, client.Options{Scheme: scheme}) |
| 245 | + if err != nil { |
| 246 | + panic(err) |
| 247 | + } |
| 248 | +} |
| 249 | + |
| 250 | +func CommonInstaller(cfg *Config) Installer { |
| 251 | + return &ClusterComponent{cfg: cfg} |
| 252 | +} |
| 253 | + |
| 254 | +type ClusterComponent struct { |
| 255 | + cfg *Config |
| 256 | +} |
| 257 | + |
| 258 | +func (c *ClusterComponent) Description() string { |
| 259 | + return fmt.Sprintf("Install %s", c.cfg.RegisterName) |
| 260 | +} |
| 261 | + |
| 262 | +func (c *ClusterComponent) Install(ctx context.Context) error { |
| 263 | + once.Do(initCli) |
| 264 | + componentPlan := v1alpha1.ComponentPlan{} |
| 265 | + if err := yaml.Unmarshal([]byte(installTemplate), &componentPlan); err != nil { |
| 266 | + return err |
| 267 | + } |
| 268 | + |
| 269 | + componentPlan.SetNamespace(c.cfg.Namespace) |
| 270 | + componentPlan.SetName(c.cfg.RegisterName) |
| 271 | + componentPlan.Spec.InstallVersion = c.cfg.Version |
| 272 | + componentPlan.Spec.Name = c.cfg.RegisterName |
| 273 | + componentPlan.Spec.ComponentRef.Namespace = c.cfg.Namespace |
| 274 | + componentPlan.Spec.Creator = "system:serviceaccount:u4a-system:kubebb-core" |
| 275 | + componentPlan.Spec.ComponentRef.Name = fmt.Sprintf("%s.%s", DEFAULTINSTALLREPO, c.cfg.RegisterName) |
| 276 | + |
| 277 | + if c.cfg.RegisterName == U4A { |
| 278 | + a := strings.ReplaceAll(u4aValueYaml, "<replaced-ingress-nginx-ip>", c.cfg.NodeIP) |
| 279 | + cm := corev1.ConfigMap{ |
| 280 | + ObjectMeta: v1.ObjectMeta{ |
| 281 | + Name: "u4acm", |
| 282 | + Namespace: c.cfg.Namespace, |
| 283 | + }, |
| 284 | + Data: map[string]string{ |
| 285 | + "values.yaml": a, |
| 286 | + }, |
| 287 | + } |
| 288 | + if err := cc.Create(ctx, &cm); err != nil { |
| 289 | + return err |
| 290 | + } |
| 291 | + componentPlan.Spec.Override.ValuesFrom = []*v1alpha1.ValuesReference{ |
| 292 | + { |
| 293 | + Kind: "ConfigMap", |
| 294 | + Name: "u4acm", |
| 295 | + ValuesKey: "values.yaml", |
| 296 | + }, |
| 297 | + } |
| 298 | + } else { |
| 299 | + componentPlan.Spec.Override.Set = c.cfg.Args.Values |
| 300 | + } |
| 301 | + err := cc.Create(ctx, &componentPlan) |
| 302 | + if c.cfg.RegisterName == CLUSTERCOMPONENT { |
| 303 | + // here need to wait for cert-manager to update the core to ensure that the webhook will work. |
| 304 | + return WaitDeployment(ctx, cc, c.cfg.Namespace, []string{"cert-manager", "cert-manager-cainjector", "cert-manager-webhook", "cluster-component-ingress-nginx-controller"}, 300) |
| 305 | + } |
| 306 | + return err |
| 307 | +} |
| 308 | + |
| 309 | +func (c *ClusterComponent) Upgrade(ctx context.Context) error { |
| 310 | + // not support |
| 311 | + return nil |
| 312 | +} |
| 313 | + |
| 314 | +func (c *ClusterComponent) Uninstall(ctx context.Context) { |
| 315 | + once.Do(initCli) |
| 316 | + componentPlan := v1alpha1.ComponentPlan{ |
| 317 | + ObjectMeta: v1.ObjectMeta{ |
| 318 | + Name: c.cfg.RegisterName, |
| 319 | + Namespace: c.cfg.Namespace, |
| 320 | + }, |
| 321 | + } |
| 322 | + _ = cc.Delete(ctx, &componentPlan) |
| 323 | +} |
0 commit comments