Weisen Pan a877aed45f AI-based CFN Traffic Control and Computer Force Scheduling
Change-Id: I16cd7730c1e0732253ac52f51010f6b813295aa7
2023-11-03 00:09:19 -07:00

122 lines
3.3 KiB
Go

package chart
// Author: Weisen Pan
// Date: 2023-10-24
import (
"bytes"
"fmt"
"path"
"strings"
simontype "github.com/hkust-adsl/kubernetes-scheduler-simulator/knets_pkg/type"
"helm.sh/helm/v3/knets_pkg/chart"
"helm.sh/helm/v3/knets_pkg/chart/loader"
"helm.sh/helm/v3/knets_pkg/chartutil"
"helm.sh/helm/v3/knets_pkg/engine"
"helm.sh/helm/v3/knets_pkg/releaseutil"
)
// ProcessChart parses a chart and returns rendered resources.
func ProcessChart(name string, chartPath string) ([]string, error) {
// Load the requested chart from the provided path.
chartRequested, err := loader.Load(chartPath)
if err != nil {
return nil, err
}
chartRequested.Metadata.Name = name
// Check if the chart is installable.
if err := checkIfInstallable(chartRequested); err != nil {
return nil, err
}
// TODO: Define values to be processed.
var vals map[string]interface{}
// Process chart dependencies.
if err := chartutil.ProcessDependencies(chartRequested, vals); err != nil {
return nil, err
}
// Convert values and render resources.
valuesToRender, err := ToRenderValues(chartRequested, vals)
if err != nil {
return nil, err
}
return renderResources(chartRequested, valuesToRender, true)
}
// checkIfInstallable validates if a chart can be installed.
// Application chart type is the only type considered installable.
func checkIfInstallable(ch *chart.Chart) error {
switch ch.Metadata.Type {
case "", "application":
return nil
}
return fmt.Errorf("%s charts are not installable", ch.Metadata.Type)
}
// ToRenderValues composes the struct from the data coming from the Releases, Charts, and Values files.
func ToRenderValues(chrt *chart.Chart, chrtVals map[string]interface{}) (chartutil.Values, error) {
top := map[string]interface{}{
"Chart": chrt.Metadata,
"Release": map[string]interface{}{
"Name": chrt.Name(),
"Namespace": "default",
"Revision": 1,
"Service": "Helm",
},
}
vals, err := chartutil.CoalesceValues(chrt, chrtVals)
if err != nil {
return top, err
}
if err := chartutil.ValidateAgainstSchema(chrt, vals); err != nil {
errFmt := "values don't meet the specifications of the schema(s) in the following chart(s):\n%s"
return top, fmt.Errorf(errFmt, err.Error())
}
top["Values"] = vals
return top, nil
}
// renderResources renders the resources from the chart.
func renderResources(ch *chart.Chart, values chartutil.Values, subNotes bool) ([]string, error) {
files, err := engine.Render(ch, values)
if err != nil {
return nil, err
}
// NOTES.txt gets rendered like all the other files but is treated separately.
var notesBuffer bytes.Buffer
for k, v := range files {
if strings.HasSuffix(k, simontype.NotesFileSuffix) {
if subNotes || (k == path.Join(ch.Name(), "templates", simontype.NotesFileSuffix)) {
// If the buffer contains data, add a newline before adding more.
if notesBuffer.Len() > 0 {
notesBuffer.WriteString("\n")
}
notesBuffer.WriteString(v)
}
delete(files, k)
}
}
// Sort hooks and manifests and return only manifests.
var yamlStr []string
_, manifests, err := releaseutil.SortManifests(files, []string{}, releaseutil.InstallOrder)
if err != nil {
return nil, err
}
for _, item := range manifests {
yamlStr = append(yamlStr, item.Content)
}
return yamlStr, nil
}