Skip to content

Commit

Permalink
add thick chart builtin collection (chart with required images)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshrwolf committed Nov 11, 2021
1 parent 20cd37e commit 4ee6129
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 36 deletions.
22 changes: 13 additions & 9 deletions cmd/hauler/cli/store/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra"

"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
"github.com/rancherfederal/hauler/pkg/artifact"
"github.com/rancherfederal/hauler/pkg/cache"
"github.com/rancherfederal/hauler/pkg/content/chart"
"github.com/rancherfederal/hauler/pkg/content/file"
Expand Down Expand Up @@ -54,17 +55,18 @@ func storeFile(ctx context.Context, s *store.Store, c cache.Cache, fi v1alpha1.F
return err
}

var oci artifact.OCI
if c != nil {
cf := cache.Oci(f, c)
f = cf
cached := cache.Oci(f, c)
oci = cached
}

ref, err := name.ParseReference(fi.Name, name.WithDefaultRegistry(""))
if err != nil {
return err
}

desc, err := s.AddArtifact(ctx, f, ref)
desc, err := s.AddArtifact(ctx, oci, ref)
if err != nil {
return err
}
Expand Down Expand Up @@ -109,12 +111,13 @@ func storeImage(ctx context.Context, s *store.Store, c cache.Cache, i v1alpha1.I
return err
}

var oci artifact.OCI
if c != nil {
ci := cache.Oci(img, c)
img = ci
cached := cache.Oci(img, c)
oci = cached
}

desc, err := s.AddArtifact(ctx, img, ref)
desc, err := s.AddArtifact(ctx, oci, ref)
if err != nil {
return err
}
Expand Down Expand Up @@ -180,12 +183,13 @@ func storeChart(ctx context.Context, s *store.Store, c cache.Cache, ch v1alpha1.
return err
}

var oci artifact.OCI
if c != nil {
cch := cache.Oci(chrt, c)
chrt = cch
cached := cache.Oci(chrt, c)
oci = cached
}

desc, err := s.AddArtifact(ctx, chrt, ref)
desc, err := s.AddArtifact(ctx, oci, ref)
if err != nil {
return err
}
Expand Down
18 changes: 18 additions & 0 deletions cmd/hauler/cli/store/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
"github.com/rancherfederal/hauler/pkg/cache"
"github.com/rancherfederal/hauler/pkg/collection/chart"
"github.com/rancherfederal/hauler/pkg/collection/k3s"
"github.com/rancherfederal/hauler/pkg/content"
"github.com/rancherfederal/hauler/pkg/log"
Expand Down Expand Up @@ -127,6 +128,23 @@ func SyncCmd(ctx context.Context, o *SyncOpts, s *store.Store, c cache.Cache) er
return err
}

case v1alpha1.ChartsCollectionKind:
var cfg v1alpha1.ThickCharts
if err := yaml.Unmarshal(doc, &cfg); err != nil {
return err
}

for _, cfg := range cfg.Spec.Charts {
tc, err := chart.NewChart(cfg.Name, cfg.RepoURL, cfg.Version)
if err != nil {
return err
}

if _, err := s.AddCollection(ctx, tc); err != nil {
return err
}
}

default:
return fmt.Errorf("unrecognized content/collection type: %s", obj.GroupVersionKind().String())
}
Expand Down
22 changes: 21 additions & 1 deletion pkg/apis/hauler.cattle.io/v1alpha1/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const ChartsContentKind = "Charts"
const (
ChartsContentKind = "Charts"
ChartsCollectionKind = "ThickCharts"
)

type Charts struct {
*metav1.TypeMeta `json:",inline"`
Expand All @@ -22,3 +25,20 @@ type Chart struct {
RepoURL string `json:"repoURL"`
Version string `json:"version"`
}

type ThickCharts struct {
*metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ChartSpec `json:"spec,omitempty"`
}

type ThickChartSpec struct {
ThickCharts []ThickChart `json:"charts,omitempty"`
}

type ThickChart struct {
Name string `json:"name"`
RepoURL string `json:"repoURL"`
Version string `json:"version"`
}
78 changes: 78 additions & 0 deletions pkg/collection/chart/chart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package chart

import (
gname "github.com/google/go-containerregistry/pkg/name"

"github.com/rancherfederal/hauler/pkg/artifact"
"github.com/rancherfederal/hauler/pkg/content/chart"
"github.com/rancherfederal/hauler/pkg/content/image"
)

var _ artifact.Collection = (*tchart)(nil)

// tchart is a thick chart that includes all the dependent images as well as the chart itself
type tchart struct {
chart *chart.Chart

computed bool
contents map[gname.Reference]artifact.OCI
}

func NewChart(name, repo, version string) (artifact.Collection, error) {
o, err := chart.NewChart(name, repo, version)
if err != nil {
return nil, err
}

return &tchart{
chart: o,
contents: make(map[gname.Reference]artifact.OCI),
}, nil
}

func (c *tchart) Contents() (map[gname.Reference]artifact.OCI, error) {
if err := c.compute(); err != nil {
return nil, err
}
return c.contents, nil
}

func (c *tchart) compute() error {
if c.computed {
return nil
}

if err := c.dependentImages(); err != nil {
return err
}

c.computed = true
return nil
}

func (c *tchart) dependentImages() error {
ch, err := c.chart.Load()
if err != nil {
return err
}

imgs, err := ImagesInChart(ch)
if err != nil {
return err
}

for _, img := range imgs.Spec.Images {
ref, err := gname.ParseReference(img.Ref)
if err != nil {
return err
}

i, err := image.NewImage(img.Ref)
if err != nil {
return err
}
c.contents[ref] = i
}

return nil
}
File renamed without changes.
16 changes: 8 additions & 8 deletions pkg/collection/k3s/k3s.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,23 @@ type k3s struct {
version string
arch string

computed bool
components map[name.Reference]artifact.OCI
channels map[string]string
computed bool
contents map[name.Reference]artifact.OCI
channels map[string]string
}

func NewK3s(version string) (artifact.Collection, error) {
return &k3s{
version: version,
components: make(map[name.Reference]artifact.OCI),
version: version,
contents: make(map[name.Reference]artifact.OCI),
}, nil
}

func (k *k3s) Contents() (map[name.Reference]artifact.OCI, error) {
if err := k.compute(); err != nil {
return nil, err
}
return k.components, nil
return k.contents, nil
}

func (k *k3s) compute() error {
Expand Down Expand Up @@ -99,7 +99,7 @@ func (k *k3s) executable() error {
return err
}

k.components[ref] = f
k.contents[ref] = f
return nil
}

Expand All @@ -124,7 +124,7 @@ func (k *k3s) images() error {
return err
}

k.components[ref] = o
k.contents[ref] = o
}
return nil
}
Expand Down
37 changes: 21 additions & 16 deletions pkg/content/chart/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
gtypes "github.com/google/go-containerregistry/pkg/v1/types"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli"

Expand All @@ -20,20 +21,15 @@ import (
"github.com/rancherfederal/hauler/pkg/artifact/types"
)

const (
// ChartLayerMediaType is the reserved media type for Helm chart package content
ChartLayerMediaType = "application/vnd.cncf.helm.chart.content.v1.tar+gzip"
)

var _ artifact.OCI = (*chrt)(nil)
var _ artifact.OCI = (*Chart)(nil)

type chrt struct {
type Chart struct {
path string

annotations map[string]string
}

func NewChart(name, repo, version string) (artifact.OCI, error) {
func NewChart(name, repo, version string) (*Chart, error) {
cpo := action.ChartPathOptions{
RepoURL: repo,
Version: version,
Expand All @@ -44,16 +40,16 @@ func NewChart(name, repo, version string) (artifact.OCI, error) {
return nil, err
}

return &chrt{
return &Chart{
path: cp,
}, nil
}

func (h *chrt) MediaType() string {
func (h *Chart) MediaType() string {
return types.OCIManifestSchema1
}

func (h *chrt) Manifest() (*gv1.Manifest, error) {
func (h *Chart) Manifest() (*gv1.Manifest, error) {
cfgDesc, err := h.configDescriptor()
if err != nil {
return nil, err
Expand All @@ -78,15 +74,15 @@ func (h *chrt) Manifest() (*gv1.Manifest, error) {
}, nil
}

func (h *chrt) RawConfig() ([]byte, error) {
func (h *Chart) RawConfig() ([]byte, error) {
ch, err := loader.Load(h.path)
if err != nil {
return nil, err
}
return json.Marshal(ch.Metadata)
}

func (h *chrt) configDescriptor() (gv1.Descriptor, error) {
func (h *Chart) configDescriptor() (gv1.Descriptor, error) {
data, err := h.RawConfig()
if err != nil {
return gv1.Descriptor{}, err
Expand All @@ -104,7 +100,16 @@ func (h *chrt) configDescriptor() (gv1.Descriptor, error) {
}, nil
}

func (h *chrt) Layers() ([]gv1.Layer, error) {
func (h *Chart) Load() (*chart.Chart, error) {
rc, err := chartOpener(h.path)()
if err != nil {
return nil, err
}
defer rc.Close()
return loader.LoadArchive(rc)
}

func (h *Chart) Layers() ([]gv1.Layer, error) {
chartDataLayer, err := h.chartDataLayer()
if err != nil {
return nil, err
Expand All @@ -116,11 +121,11 @@ func (h *chrt) Layers() ([]gv1.Layer, error) {
}, nil
}

func (h *chrt) RawChartData() ([]byte, error) {
func (h *Chart) RawChartData() ([]byte, error) {
return os.ReadFile(h.path)
}

func (h *chrt) chartDataLayer() (gv1.Layer, error) {
func (h *Chart) chartDataLayer() (gv1.Layer, error) {
annotations := make(map[string]string)
annotations[ocispec.AnnotationTitle] = filepath.Base(h.path)

Expand Down
2 changes: 1 addition & 1 deletion pkg/content/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type file struct {
annotations map[string]string
}

func NewFile(ref string, filename string) (artifact.OCI, error) {
func NewFile(ref string, filename string) (*file, error) {
var getter local.Opener
if strings.HasPrefix(ref, "http") || strings.HasPrefix(ref, "https") {
getter = remoteOpener(ref)
Expand Down
2 changes: 1 addition & 1 deletion pkg/content/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type image struct {
gv1.Image
}

func NewImage(ref string) (artifact.OCI, error) {
func NewImage(ref string) (*image, error) {
r, err := name.ParseReference(ref)
if err != nil {
return nil, err
Expand Down
11 changes: 11 additions & 0 deletions testdata/chart-collection.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: collection.hauler.cattle.io/v1alpha1
kind: ThickCharts
metadata:
name: mythickchart
spec:
charts:
# charts are also fetched and served as OCI content (currently experimental in helm)
# HELM_EXPERIMENTAL_OCI=1 helm chart pull <hauler-registry>/loki:2.6.2
- name: loki
repoURL: https://grafana.github.io/helm-charts

0 comments on commit 4ee6129

Please sign in to comment.