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

Support NSM's helm charts repo #53

Closed
leecalcote opened this issue Feb 6, 2020 · 4 comments
Closed

Support NSM's helm charts repo #53

leecalcote opened this issue Feb 6, 2020 · 4 comments
Labels
issue/remind Issue progress check kind/enhancement Improvement in current feature

Comments

@leecalcote
Copy link
Member

Enhancement Description
The current design the NSM adapter is using for deployments is somewhat fragile. Using helm install will insulate Meshery from movement of charts directories and it will have the affect of Meshery only installing NSM releases, not intermediate versions of charts between releases.

Related Challenges


[Optional] Alternatives
A brief description of any alternative solutions or features you've considered.

[Optional] Additional context
Add any other context or screenshots about the feature request here.feature

@leecalcote leecalcote added the kind/enhancement Improvement in current feature label Feb 6, 2020
@girishranganathan
Copy link
Contributor

girishranganathan commented Feb 6, 2020

Here is a POC code which fetches charts from NSM helm repo and generates manifests which can then be given to the adapter to apply on the cluster:

package main

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"

	"github.com/sirupsen/logrus"
	"k8s.io/helm/pkg/chartutil"
	"k8s.io/helm/pkg/getter"
	"k8s.io/helm/pkg/manifest"
	"k8s.io/helm/pkg/proto/hapi/chart"
	"github.com/pkg/errors"
	"k8s.io/helm/pkg/helm/environment"
	"k8s.io/helm/pkg/renderutil"
	"k8s.io/helm/pkg/repo"
	"k8s.io/helm/pkg/tiller"
	"k8s.io/helm/pkg/timeconv"
)

var (
	destinationFolder = path.Join(os.TempDir(), "NSM")
)

func addRepository(name, repoURL string) (*repo.IndexFile, error) {
	chRepo, err := repo.NewChartRepository(&repo.Entry{
		Name: name,
		URL:  repoURL,
		// Cache: destinationFolder,
	}, getter.All(environment.EnvSettings{}))
	if err != nil {
		err = errors.Wrapf(err, "creating new chart repo failed")
		logrus.Error(err)
		return nil, err
	}
	logrus.Infof("ch repo: %+v", chRepo)
	folderName := path.Join(destinationFolder, name)
	fileName := path.Join(folderName, "index.yaml")
	_, err = os.Stat(folderName)
	if err != nil {
		if os.IsNotExist(err) {
			err := os.MkdirAll(folderName, os.ModePerm)
			if err != nil {
				err = errors.Wrapf(err, "unable to create a folder: %s", folderName)
				logrus.Error(err)
				return nil, err
			}
		} else {
			err = errors.Wrapf(err, "unknown error")
			logrus.Error(err)
			return nil, err
		}
	}
	logrus.Debugf("fileName: %s", fileName)
	if err := chRepo.DownloadIndexFile(fileName); err != nil {
		err = errors.Wrapf(err, "error downloading index file from repo")
		logrus.Error(err)
		return nil, err
	}

	indexFile, err := repo.LoadIndexFile(fileName)
	if err != nil {
		err = errors.Wrapf(err, "unable to load index file: %s", fileName)
		logrus.Error(err)
		return nil, err
	}
	logrus.Debugf("index file: %+v", indexFile)
	return indexFile, nil
}

func retrieveURLForChart(indexFile *repo.IndexFile, repoURL, cName, cVersion string) (string, error) {
	chartVersion, err := indexFile.Get(cName, cVersion) // version can be left empty to get the latest
	if err != nil {
		err = errors.Wrapf(err, "unable to get chart info for the requested chart name: %s, version: %s", cName, cVersion)
		logrus.Error(err)
		return "", nil
	}

	logrus.Debugf("Retrieved app version: %s", chartVersion.GetAppVersion())
	logrus.Debugf("Retreived source url: %s", chartVersion.URLs)

	if len(chartVersion.URLs) > 0 {
		mainRepoURLPath := chartVersion.URLs[0]
		mainRepoURL, _ := url.Parse(mainRepoURLPath)
		if mainRepoURL.IsAbs() {
			logrus.Debugf("final repo url: %s", mainRepoURL)
			return mainRepoURL.String(), nil
		} else {
			hURL := mainRepoURLPath
			if strings.HasSuffix(repoURL, "/") {
				hURL = repoURL + hURL
			} else {
				hURL = repoURL + "/" + hURL
			}
			mainRepoURL, _ := url.Parse(hURL)
			if mainRepoURL.IsAbs() {
				logrus.Debugf("final repo url: %s", mainRepoURL)
				return mainRepoURL.String(), nil
			}
		}
	}
	err = errors.New("unable to locate the repo download url")
	logrus.Error(err)
	return "", err
}

func loadChart(repoURL string) (*chart.Chart, error) {
	var ch *chart.Chart
	var err error
	if strings.HasPrefix(repoURL, "http://") || strings.HasPrefix(repoURL, "https://") {
		logrus.Debugf("fetching chart from url: %s", repoURL)
		var resp *http.Response
		resp, err = http.Get(repoURL)
		if err == nil {
			defer resp.Body.Close()
			ch, err = chartutil.LoadArchive(resp.Body)
		}
	} else {
		ch, err = chartutil.LoadDir(repoURL)
	}
	if err != nil {
		err = errors.Wrapf(err, "chart load error")
		logrus.Error(err)
		return nil, err
	}
	logrus.Debugf("chart: %+v", ch)
	return ch, nil
}

func renderManifests(ctx context.Context, c *chart.Chart, releaseName, namespace, kubeVersion, customConfig string) ([]manifest.Manifest, error) {
	if strings.TrimSpace(customConfig) != "" {
		c.Values.Raw = customConfig
	}
	renderOpts := renderutil.Options{
		ReleaseOptions: chartutil.ReleaseOptions{
			Name:      releaseName,
			IsInstall: true,
			Time:      timeconv.Now(),
			Namespace: namespace,
		},
		KubeVersion: kubeVersion,
	}
	config := &chart.Config{Raw: "{}", Values: map[string]*chart.Value{}}

	renderedTemplates, err := renderutil.Render(c, config, renderOpts)
	if err != nil {
		return nil, err
	}
	manifests := manifest.SplitManifests(renderedTemplates)
	return tiller.SortByKind(manifests), nil
}

func main() {
	logrus.SetLevel(logrus.DebugLevel)
	logrus.Infof("destination folder: %s", destinationFolder)
	baseRepoURL := "https://helm.nsm.dev/master"
	indexFile, err := addRepository("nsm", baseRepoURL)
	if err != nil {
		logrus.Fatal(err)
	}
	// chartName := "nsm"
	chartName := "icmp-responder"

	repoURL, err := retrieveURLForChart(indexFile, baseRepoURL, chartName, "")
	if err != nil {
		logrus.Fatal(err)
	}
	ch, err := loadChart(repoURL)
	if err != nil {
		logrus.Fatal(err)
	}
	manifests, err := renderManifests(context.Background(), ch, chartName, "nsm", "", "")
	if err != nil {
		logrus.Fatal(err)
	}
	logrus.Infof("Generate manifests:")
	for _, manifest := range manifests {
		fmt.Printf("%s\n", manifest.Content)
	}
}

@leecalcote
Copy link
Member Author

@ivanayov would you like to have a look here?

@iambami iambami added the issue/remind Issue progress check label Jan 14, 2022
@iambami
Copy link

iambami commented Jan 14, 2022

Hi, @nveenjain are you still working on this issue?

@nveenjain
Copy link

Hey @iambami , No, feel free to take up this issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue/remind Issue progress check kind/enhancement Improvement in current feature
Projects
None yet
Development

No branches or pull requests

4 participants