Esempio n. 1
0
// loadChartRepositories reads the repositories.yaml, and then builds a map of
// ChartRepositories.
//
// The key is the local name (which is only present in the repositories.yaml).
func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, error) {
	indices := map[string]*repo.ChartRepository{}
	repoyaml := m.HelmHome.RepositoryFile()

	// Load repositories.yaml file
	rf, err := repo.LoadRepositoriesFile(repoyaml)
	if err != nil {
		return indices, fmt.Errorf("failed to load %s: %s", repoyaml, err)
	}

	for _, re := range rf.Repositories {
		lname := re.Name
		cacheindex := m.HelmHome.CacheIndex(lname)
		index, err := repo.LoadIndexFile(cacheindex)
		if err != nil {
			return indices, err
		}

		cr := &repo.ChartRepository{
			URL:       re.URL,
			IndexFile: index,
		}
		indices[lname] = cr
	}
	return indices, nil
}
Esempio n. 2
0
func TestRepoIndexCmd(t *testing.T) {

	dir, err := ioutil.TempDir("", "helm-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	if err := os.Link("testdata/testcharts/compressedchart-0.1.0.tgz", filepath.Join(dir, "compressedchart-0.1.0.tgz")); err != nil {
		t.Fatal(err)
	}

	buf := bytes.NewBuffer(nil)
	c := newRepoIndexCmd(buf)

	if err := c.RunE(c, []string{dir}); err != nil {
		t.Errorf("%q", err)
	}

	index, err := repo.LoadIndexFile(filepath.Join(dir, "index.yaml"))
	if err != nil {
		t.Fatal(err)
	}

	if len(index.Entries) != 1 {
		t.Errorf("expected 1 entry, got %v: %#v", len(index.Entries), index.Entries)
	}

}
Esempio n. 3
0
func searchCacheForPattern(dir string, search string) ([]string, error) {
	fileList := []string{}
	filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if !f.IsDir() {
			fileList = append(fileList, path)
		}
		return nil
	})
	matches := []string{}
	for _, f := range fileList {
		index, err := repo.LoadIndexFile(f)
		if err != nil {
			return matches, fmt.Errorf("index %s corrupted: %s", f, err)
		}

		m := searchChartRefsForPattern(search, index.Entries)
		repoName := strings.TrimSuffix(filepath.Base(f), "-index.yaml")
		for _, c := range m {
			// TODO: Is it possible for this file to be missing? Or to have
			// an extension other than .tgz? Should the actual filename be in
			// the YAML?
			fname := filepath.Join(repoName, c+".tgz")
			matches = append(matches, fname)
		}
	}
	return matches, nil
}
Esempio n. 4
0
// Resolve resolves dependencies and returns a lock file with the resolution.
func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]string) (*chartutil.RequirementsLock, error) {
	d, err := HashReq(reqs)
	if err != nil {
		return nil, err
	}

	// Now we clone the dependencies, locking as we go.
	locked := make([]*chartutil.Dependency, len(reqs.Dependencies))
	missing := []string{}
	for i, d := range reqs.Dependencies {
		constraint, err := semver.NewConstraint(d.Version)
		if err != nil {
			return nil, fmt.Errorf("dependency %q has an invalid version/constraint format: %s", d.Name, err)
		}

		repoIndex, err := repo.LoadIndexFile(r.helmhome.CacheIndex(repoNames[d.Name]))
		if err != nil {
			return nil, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err)
		}

		vs, ok := repoIndex.Entries[d.Name]
		if !ok {
			return nil, fmt.Errorf("%s chart not found in repo %s", d.Name, d.Repository)
		}

		locked[i] = &chartutil.Dependency{
			Name:       d.Name,
			Repository: d.Repository,
		}
		found := false
		// The version are already sorted and hence the first one to satisfy the constraint is used
		for _, ver := range vs {
			v, err := semver.NewVersion(ver.Version)
			if err != nil || len(ver.URLs) == 0 {
				// Not a legit entry.
				continue
			}
			if constraint.Check(v) {
				found = true
				locked[i].Version = v.Original()
				break
			}
		}

		if !found {
			missing = append(missing, d.Name)
		}
	}
	if len(missing) > 0 {
		return nil, fmt.Errorf("Can't get a valid version for repositories %s. Try changing the version constraint in requirements.yaml", strings.Join(missing, ", "))
	}
	return &chartutil.RequirementsLock{
		Generated:    time.Now(),
		Digest:       d,
		Dependencies: locked,
	}, nil
}
Esempio n. 5
0
func searchTestRunner(t *testing.T, tc searchTestCase) {
	cf, err := repo.LoadIndexFile(testFile)
	if err != nil {
		t.Errorf("Failed to load index file : %s : %s", testFile, err)
	}

	u := searchChartRefsForPattern(tc.in, cf.Entries)
	validateEntries(t, tc.in, u, tc.expectedOut)
}
Esempio n. 6
0
// ResolveChartVersion resolves a chart reference to a URL.
//
// A reference may be an HTTP URL, a 'reponame/chartname' reference, or a local path.
//
// A version is a SemVer string (1.2.3-beta.1+f334a6789).
//
// 	- For fully qualified URLs, the version will be ignored (since URLs aren't versioned)
//	- For a chart reference
//		* If version is non-empty, this will return the URL for that version
//		* If version is empty, this will return the URL for the latest version
// 		* If no version can be found, an error is returned
func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, error) {
	// See if it's already a full URL.
	// FIXME: Why do we use url.ParseRequestURI instead of url.Parse?
	u, err := url.ParseRequestURI(ref)
	if err == nil {
		// If it has a scheme and host and path, it's a full URL
		if u.IsAbs() && len(u.Host) > 0 && len(u.Path) > 0 {
			return u, nil
		}
		return u, fmt.Errorf("invalid chart url format: %s", ref)
	}

	r, err := repo.LoadRepositoriesFile(c.HelmHome.RepositoryFile())
	if err != nil {
		return u, err
	}

	// See if it's of the form: repo/path_to_chart
	p := strings.SplitN(ref, "/", 2)
	if len(p) < 2 {
		return u, fmt.Errorf("invalid chart url format: %s", ref)
	}

	repoName := p[0]
	chartName := p[1]
	rf, err := findRepoEntry(repoName, r.Repositories)
	if err != nil {
		return u, err
	}
	if rf.URL == "" {
		return u, fmt.Errorf("no URL found for repository %q", repoName)
	}

	// Next, we need to load the index, and actually look up the chart.
	i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(repoName))
	if err != nil {
		return u, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err)
	}

	cv, err := i.Get(chartName, version)
	if err != nil {
		return u, fmt.Errorf("chart %q not found in %s index. (try 'helm repo update'). %s", chartName, repoName, err)
	}

	if len(cv.URLs) == 0 {
		return u, fmt.Errorf("chart %q has no downloadable URLs", ref)
	}
	return url.Parse(cv.URLs[0])
}
Esempio n. 7
0
func index(dir, url, mergeTo string) error {
	chartRepo, err := repo.LoadChartRepository(dir, url)
	if err != nil {
		return err
	}

	if mergeTo != "" {
		old, err := repo.LoadIndexFile(mergeTo)
		if err != nil {
			return err
		}
		return chartRepo.MergeIndex(old)
	}

	return chartRepo.Index()
}
Esempio n. 8
0
func index(dir, url, mergeTo string) error {
	out := filepath.Join(dir, "index.yaml")

	i, err := repo.IndexDirectory(dir, url)
	if err != nil {
		return err
	}
	if mergeTo != "" {
		i2, err := repo.LoadIndexFile(mergeTo)
		if err != nil {
			return fmt.Errorf("Merge failed: %s", err)
		}
		i.Merge(i2)
	}
	i.SortEntries()
	return i.WriteFile(out, 0755)
}
Esempio n. 9
0
func (s *searchCmd) buildIndex() (*search.Index, error) {
	// Load the repositories.yaml
	rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile())
	if err != nil {
		return nil, err
	}

	i := search.NewIndex()
	for n := range rf.Repositories {
		f := s.helmhome.CacheIndex(n)
		ind, err := repo.LoadIndexFile(f)
		if err != nil {
			fmt.Fprintf(s.out, "WARNING: Repo %q is corrupt. Try 'helm update': %s", f, err)
			continue
		}

		i.AddRepo(n, ind)
	}
	return i, nil
}
Esempio n. 10
0
func (s *searchCmd) buildIndex() (*search.Index, error) {
	// Load the repositories.yaml
	rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile())
	if err != nil {
		return nil, err
	}

	i := search.NewIndex()
	for _, re := range rf.Repositories {
		n := re.Name
		f := s.helmhome.CacheIndex(n)
		ind, err := repo.LoadIndexFile(f)
		if err != nil {
			fmt.Fprintf(s.out, "WARNING: Repo %q is corrupt or missing. Try 'helm repo update'.", n)
			continue
		}

		i.AddRepo(n, ind, s.versions)
	}
	return i, nil
}
Esempio n. 11
0
func TestDependencyUpdateCmd(t *testing.T) {
	// Set up a testing helm home
	oldhome := helmHome
	hh, err := tempHelmHome()
	if err != nil {
		t.Fatal(err)
	}
	helmHome = hh
	defer func() {
		os.RemoveAll(hh)
		helmHome = oldhome
	}()

	srv := repotest.NewServer(hh)
	defer srv.Stop()
	copied, err := srv.CopyCharts("testdata/testcharts/*.tgz")
	t.Logf("Copied charts:\n%s", strings.Join(copied, "\n"))
	t.Logf("Listening on directory %s", srv.Root())

	chartname := "depup"
	if err := createTestingChart(hh, chartname, srv.URL()); err != nil {
		t.Fatal(err)
	}

	out := bytes.NewBuffer(nil)
	duc := &dependencyUpdateCmd{out: out}
	duc.helmhome = helmpath.Home(hh)
	duc.chartpath = filepath.Join(hh, chartname)

	if err := duc.run(); err != nil {
		output := out.String()
		t.Logf("Output: %s", output)
		t.Fatal(err)
	}

	output := out.String()
	// This is written directly to stdout, so we have to capture as is.
	if !strings.Contains(output, `update from the "test" chart repository`) {
		t.Errorf("Repo did not get updated\n%s", output)
	}

	// Make sure the actual file got downloaded.
	expect := filepath.Join(hh, chartname, "charts/reqtest-0.1.0.tgz")
	if _, err := os.Stat(expect); err != nil {
		t.Fatal(err)
	}

	hash, err := provenance.DigestFile(expect)
	if err != nil {
		t.Fatal(err)
	}

	i, err := repo.LoadIndexFile(cacheIndexFile("test"))
	if err != nil {
		t.Fatal(err)
	}

	if h := i.Entries["reqtest-0.1.0"].Digest; h != hash {
		t.Errorf("Failed hash match: expected %s, got %s", hash, h)
	}

	t.Logf("Results: %s", out.String())
}
Esempio n. 12
0
func TestRepoIndexCmd(t *testing.T) {

	dir, err := ioutil.TempDir("", "helm-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	comp := filepath.Join(dir, "compressedchart-0.1.0.tgz")
	if err := os.Link("testdata/testcharts/compressedchart-0.1.0.tgz", comp); err != nil {
		t.Fatal(err)
	}
	comp2 := filepath.Join(dir, "compressedchart-0.2.0.tgz")
	if err := os.Link("testdata/testcharts/compressedchart-0.2.0.tgz", comp2); err != nil {
		t.Fatal(err)
	}

	buf := bytes.NewBuffer(nil)
	c := newRepoIndexCmd(buf)

	if err := c.RunE(c, []string{dir}); err != nil {
		t.Error(err)
	}

	destIndex := filepath.Join(dir, "index.yaml")

	index, err := repo.LoadIndexFile(destIndex)
	if err != nil {
		t.Fatal(err)
	}

	if len(index.Entries) != 1 {
		t.Errorf("expected 1 entry, got %d: %#v", len(index.Entries), index.Entries)
	}

	vs := index.Entries["compressedchart"]
	if len(vs) != 2 {
		t.Errorf("expected 2 versions, got %d: %#v", len(vs), vs)
	}

	expectedVersion := "0.2.0"
	if vs[0].Version != expectedVersion {
		t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version)
	}

	// Test with `--merge`

	// Remove first two charts.
	if err := os.Remove(comp); err != nil {
		t.Fatal(err)
	}
	if err := os.Remove(comp2); err != nil {
		t.Fatal(err)
	}
	// Add a new chart and a new version of an existing chart
	if err := os.Link("testdata/testcharts/reqtest-0.1.0.tgz", filepath.Join(dir, "reqtest-0.1.0.tgz")); err != nil {
		t.Fatal(err)
	}
	if err := os.Link("testdata/testcharts/compressedchart-0.3.0.tgz", filepath.Join(dir, "compressedchart-0.3.0.tgz")); err != nil {
		t.Fatal(err)
	}

	c.ParseFlags([]string{"--merge", destIndex})
	if err := c.RunE(c, []string{dir}); err != nil {
		t.Error(err)
	}

	index, err = repo.LoadIndexFile(destIndex)
	if err != nil {
		t.Fatal(err)
	}

	if len(index.Entries) != 2 {
		t.Errorf("expected 2 entries, got %d: %#v", len(index.Entries), index.Entries)
	}

	vs = index.Entries["compressedchart"]
	if len(vs) != 3 {
		t.Errorf("expected 3 versions, got %d: %#v", len(vs), vs)
	}

	expectedVersion = "0.3.0"
	if vs[0].Version != expectedVersion {
		t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version)
	}
}
func TestDependencyBuildCmd(t *testing.T) {
	oldhome := helmHome
	hh, err := tempHelmHome(t)
	if err != nil {
		t.Fatal(err)
	}
	helmHome = hh
	defer func() {
		os.RemoveAll(hh)
		helmHome = oldhome
	}()

	srv := repotest.NewServer(hh)
	defer srv.Stop()
	_, err = srv.CopyCharts("testdata/testcharts/*.tgz")
	if err != nil {
		t.Fatal(err)
	}

	chartname := "depbuild"
	if err := createTestingChart(hh, chartname, srv.URL()); err != nil {
		t.Fatal(err)
	}

	out := bytes.NewBuffer(nil)
	dbc := &dependencyBuildCmd{out: out}
	dbc.helmhome = helmpath.Home(hh)
	dbc.chartpath = filepath.Join(hh, chartname)

	// In the first pass, we basically want the same results as an update.
	if err := dbc.run(); err != nil {
		output := out.String()
		t.Logf("Output: %s", output)
		t.Fatal(err)
	}

	output := out.String()
	if !strings.Contains(output, `update from the "test" chart repository`) {
		t.Errorf("Repo did not get updated\n%s", output)
	}

	// Make sure the actual file got downloaded.
	expect := filepath.Join(hh, chartname, "charts/reqtest-0.1.0.tgz")
	if _, err := os.Stat(expect); err != nil {
		t.Fatal(err)
	}

	// In the second pass, we want to remove the chart's request dependency,
	// then see if it restores from the lock.
	lockfile := filepath.Join(hh, chartname, "requirements.lock")
	if _, err := os.Stat(lockfile); err != nil {
		t.Fatal(err)
	}
	if err := os.RemoveAll(expect); err != nil {
		t.Fatal(err)
	}

	if err := dbc.run(); err != nil {
		output := out.String()
		t.Logf("Output: %s", output)
		t.Fatal(err)
	}

	// Now repeat the test that the dependency exists.
	expect = filepath.Join(hh, chartname, "charts/reqtest-0.1.0.tgz")
	if _, err := os.Stat(expect); err != nil {
		t.Fatal(err)
	}

	// Make sure that build is also fetching the correct version.
	hash, err := provenance.DigestFile(expect)
	if err != nil {
		t.Fatal(err)
	}

	i, err := repo.LoadIndexFile(dbc.helmhome.CacheIndex("test"))
	if err != nil {
		t.Fatal(err)
	}

	reqver := i.Entries["reqtest"][0]
	if h := reqver.Digest; h != hash {
		t.Errorf("Failed hash match: expected %s, got %s", hash, h)
	}
	if v := reqver.Version; v != "0.1.0" {
		t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v)
	}

}