Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[installer]: create a configmap with a simplified installation manifest #6591

Merged
merged 1 commit into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions installer/cmd/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,27 @@ A config file is required which can be generated with the init command.`,
}
k8s = append(k8s, charts...)

sortedCharts, err := common.DependencySortingRenderFunc(k8s)
// convert everything to individual objects
runtimeObjs, err := common.YamlToRuntimeObject(k8s)
if err != nil {
return err
}

for _, c := range sortedCharts {
fmt.Printf("---\n%s\n", c)
// generate a config map with every component installed
runtimeObjsAndConfig, err := common.GenerateInstallationConfigMap(ctx, runtimeObjs)
if err != nil {
return err
}

// sort the objects and return the plain YAML
sortedObjs, err := common.DependencySortingRenderFunc(runtimeObjsAndConfig)
if err != nil {
return err
}

// output the YAML to stdout
for _, c := range sortedObjs {
fmt.Printf("---\n# %s/%s %s\n%s\n", c.TypeMeta.APIVersion, c.TypeMeta.Kind, c.Metadata.Name, c.Content)
}

return nil
Expand Down
161 changes: 161 additions & 0 deletions installer/pkg/common/display.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Copyright (c) 2021 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package common

import (
corev1 "k8s.io/api/core/v1"
"regexp"
"sort"
"strings"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

// Those occurring earlier in the list get installed before those occurring later in the list.
// Based on Helm's list, with our CRDs added in

var sortOrder = []string{
"Namespace",
"NetworkPolicy",
"ResourceQuota",
"Issuer",
"Certificate",
"LimitRange",
"PodSecurityPolicy",
"PodDisruptionBudget",
"ServiceAccount",
"Secret",
"SecretList",
"ConfigMap",
"StorageClass",
"PersistentVolume",
"PersistentVolumeClaim",
"CustomResourceDefinition",
"ClusterRole",
"ClusterRoleList",
"ClusterRoleBinding",
"ClusterRoleBindingList",
"Role",
"RoleList",
"RoleBinding",
"RoleBindingList",
"Service",
"DaemonSet",
"Pod",
"ReplicationController",
"ReplicaSet",
"StatefulSet",
"Deployment",
"HorizontalPodAutoscaler",
"Job",
"CronJob",
"Ingress",
"APIService",
}

type RuntimeObject struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for future reference: we need to reign this back in; not export this in the future. Having our own version of what's essentially runtime.Object doesn't bode well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, agreed. I don't want this used for anything else

metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Content string `json:"-"`
}

func DependencySortingRenderFunc(objects []RuntimeObject) ([]RuntimeObject, error) {
sortMap := map[string]int{}
for k, v := range sortOrder {
sortMap[v] = k
}

sort.Slice(objects, func(i, j int) bool {
scoreI := sortMap[objects[i].Kind]
scoreJ := sortMap[objects[j].Kind]

return scoreI < scoreJ
})

return objects, nil
}

func GenerateInstallationConfigMap(ctx *RenderContext, objects []RuntimeObject) ([]RuntimeObject, error) {
cfgMapData := make([]string, 0)
component := "gitpod-app"

// Convert to a simplified object that allows us to access the objects
for _, c := range objects {
if c.Kind != "" {
marshal, err := yaml.Marshal(c)
if err != nil {
return nil, err
}

cfgMapData = append(cfgMapData, string(marshal))
}
}

cfgMap := corev1.ConfigMap{
TypeMeta: TypeMetaConfigmap,
ObjectMeta: metav1.ObjectMeta{
Name: component,
Namespace: ctx.Namespace,
Labels: DefaultLabels(component),
},
}

// generate the config map data so it can be injected to the object
marshal, err := yaml.Marshal(cfgMap)
if err != nil {
return nil, err
}

cfgMapData = append(cfgMapData, string(marshal))

// Generate the data, including this config map
cfgMap.Data = map[string]string{
"app.yaml": strings.Join(cfgMapData, "---\n"),
}

// regenerate the config map so it can be injected into the charts with this config map in
marshal, err = yaml.Marshal(cfgMap)
if err != nil {
return nil, err
}

// Add in the ConfigMap
objects = append(objects, RuntimeObject{
TypeMeta: cfgMap.TypeMeta,
Metadata: cfgMap.ObjectMeta,
Content: string(marshal),
})

return objects, nil
}

func YamlToRuntimeObject(objects []string) ([]RuntimeObject, error) {
sortedObjects := make([]RuntimeObject, 0, len(objects))
for _, o := range objects {
// Assume multi-document YAML
re := regexp.MustCompile("(^|\n)---")
items := re.Split(o, -1)

for _, p := range items {
var v RuntimeObject
err := yaml.Unmarshal([]byte(p), &v)
if err != nil {
return nil, err
}

// remove any empty charts
ctnt := strings.Trim(p, "\n")
if len(strings.TrimSpace(ctnt)) == 0 {
continue
}

v.Content = ctnt
sortedObjects = append(sortedObjects, v)
}
}

return sortedObjects, nil
}
107 changes: 0 additions & 107 deletions installer/pkg/common/sorter.go

This file was deleted.