github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/package-server/provider/registry.go (about)

     1  package provider
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"sort"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/blang/semver/v4"
    14  	operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
    15  	"github.com/operator-framework/operator-registry/pkg/api"
    16  	orregistry "github.com/operator-framework/operator-registry/pkg/registry"
    17  	"github.com/sirupsen/logrus"
    18  	"google.golang.org/grpc"
    19  	"google.golang.org/grpc/connectivity"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  	"k8s.io/apimachinery/pkg/labels"
    22  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    23  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    24  	"k8s.io/client-go/tools/cache"
    25  
    26  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
    27  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
    28  	operatorslisters "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
    29  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
    30  	registrygrpc "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc"
    31  	utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels"
    32  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
    33  	"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators"
    34  	pkglisters "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/client/listers/operators/internalversion"
    35  )
    36  
    37  const (
    38  	catalogIndex = "catalog"
    39  	cacheTimeout = 5 * time.Minute
    40  	readyTimeout = 10 * time.Minute
    41  	stateTimeout = 20 * time.Second
    42  )
    43  
    44  func getSourceKey(pkg *operators.PackageManifest) (key *registry.CatalogKey) {
    45  	if pkg != nil {
    46  		key = &registry.CatalogKey{
    47  			Namespace: pkg.Status.CatalogSourceNamespace,
    48  			Name:      pkg.Status.CatalogSource,
    49  		}
    50  	}
    51  
    52  	return
    53  }
    54  
    55  func catalogIndexFunc(obj interface{}) ([]string, error) {
    56  	pkg, ok := obj.(*operators.PackageManifest)
    57  	if !ok {
    58  		return []string{""}, fmt.Errorf("obj is not a packagemanifest %v", obj)
    59  	}
    60  
    61  	return []string{getSourceKey(pkg).String()}, nil
    62  }
    63  
    64  func PackageManifestKeyFunc(obj interface{}) (string, error) {
    65  	if key, ok := obj.(string); ok {
    66  		return key, nil
    67  	}
    68  
    69  	pkg, ok := obj.(*operators.PackageManifest)
    70  	if !ok {
    71  		return "", fmt.Errorf("obj is not a packagemanifest %v", obj)
    72  	}
    73  
    74  	return pkg.Status.CatalogSource + "/" + pkg.GetNamespace() + "/" + pkg.GetName(), nil
    75  }
    76  
    77  func SplitPackageManifestKey(key string) (catsrcname, namespace, name string, err error) {
    78  	parts := strings.Split(key, "/")
    79  	switch len(parts) {
    80  	case 3:
    81  		// catalogsource name, namespace and packagemanifest name
    82  		return parts[0], parts[1], parts[2], nil
    83  	}
    84  
    85  	return "", "", "", fmt.Errorf("unexpected key format: %q", key)
    86  }
    87  
    88  type registryClient struct {
    89  	api.RegistryClient
    90  	catsrc *operatorsv1alpha1.CatalogSource
    91  	conn   *grpc.ClientConn
    92  }
    93  
    94  func newRegistryClient(catsrc *operatorsv1alpha1.CatalogSource, conn *grpc.ClientConn) *registryClient {
    95  	return &registryClient{
    96  		RegistryClient: api.NewRegistryClient(conn),
    97  		catsrc:         catsrc,
    98  		conn:           conn,
    99  	}
   100  }
   101  
   102  func (r *registryClient) key() (key registry.CatalogKey, err error) {
   103  	if r.catsrc == nil {
   104  		err = fmt.Errorf("cannot get key, nil catalog")
   105  		return
   106  	}
   107  
   108  	key = registry.CatalogKey{
   109  		Namespace: r.catsrc.GetNamespace(),
   110  		Name:      r.catsrc.GetName(),
   111  	}
   112  
   113  	return
   114  }
   115  
   116  // RegistryProvider aggregates several `CatalogSources` and establishes gRPC connections to their registry servers.
   117  type RegistryProvider struct {
   118  	queueinformer.Operator
   119  	runOnce sync.Once
   120  
   121  	globalNamespace string
   122  	sources         *registrygrpc.SourceStore
   123  	cache           cache.Indexer
   124  	pkgLister       pkglisters.PackageManifestLister
   125  	catsrcLister    operatorslisters.CatalogSourceLister
   126  }
   127  
   128  var _ PackageManifestProvider = &RegistryProvider{}
   129  
   130  func NewRegistryProvider(ctx context.Context, crClient versioned.Interface, operator queueinformer.Operator, wakeupInterval time.Duration, globalNamespace string) (*RegistryProvider, error) {
   131  	p := &RegistryProvider{
   132  		Operator: operator,
   133  
   134  		globalNamespace: globalNamespace,
   135  		cache: cache.NewIndexer(PackageManifestKeyFunc, cache.Indexers{
   136  			cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
   137  			catalogIndex:         catalogIndexFunc,
   138  		}),
   139  	}
   140  	p.sources = registrygrpc.NewSourceStore(logrus.New(), stateTimeout, readyTimeout, p.syncSourceState)
   141  	p.pkgLister = pkglisters.NewPackageManifestLister(p.cache)
   142  
   143  	// Register queue and QueueInformer
   144  	informerFactory := externalversions.NewSharedInformerFactoryWithOptions(crClient, wakeupInterval, externalversions.WithNamespace(metav1.NamespaceAll))
   145  	catsrcInformer := informerFactory.Operators().V1alpha1().CatalogSources()
   146  	catsrcQueueInformer, err := queueinformer.NewQueueInformer(
   147  		ctx,
   148  		queueinformer.WithInformer(catsrcInformer.Informer()),
   149  		queueinformer.WithSyncer(queueinformer.LegacySyncHandler(p.syncCatalogSource).ToSyncerWithDelete(p.catalogSourceDeleted)),
   150  	)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	if err := p.RegisterQueueInformer(catsrcQueueInformer); err != nil {
   155  		return nil, err
   156  	}
   157  	p.catsrcLister = catsrcInformer.Lister()
   158  
   159  	return p, nil
   160  }
   161  
   162  // Run starts the provider's source connection management and catalog informers without blocking.
   163  func (p *RegistryProvider) Run(ctx context.Context) {
   164  	p.runOnce.Do(func() {
   165  		// Both are non-blocking
   166  		p.sources.Start(ctx)
   167  		p.Operator.Run(ctx)
   168  	})
   169  }
   170  
   171  func (p *RegistryProvider) syncCatalogSource(obj interface{}) (syncError error) {
   172  	source, ok := obj.(*operatorsv1alpha1.CatalogSource)
   173  	if !ok {
   174  		logrus.Errorf("catalogsource type assertion failed: wrong type: %#v", obj)
   175  	}
   176  
   177  	logger := logrus.WithFields(logrus.Fields{
   178  		"action":    "sync catalogsource",
   179  		"name":      source.GetName(),
   180  		"namespace": source.GetNamespace(),
   181  	})
   182  
   183  	if source.Status.RegistryServiceStatus == nil {
   184  		logger.Debug("registry service is not ready for grpc connection")
   185  		return
   186  	}
   187  
   188  	address := source.Address()
   189  	logger = logger.WithField("address", address)
   190  
   191  	key := registry.CatalogKey{
   192  		Namespace: source.GetNamespace(),
   193  		Name:      source.GetName(),
   194  	}
   195  
   196  	if sourceMeta := p.sources.GetMeta(key); sourceMeta != nil && sourceMeta.Address == address {
   197  		logger.Infof("updating PackageManifest based on CatalogSource changes: %v", key)
   198  		timeout, cancel := context.WithTimeout(context.Background(), cacheTimeout)
   199  		defer cancel()
   200  		var client *registryClient
   201  		client, syncError = p.registryClient(key)
   202  		if syncError != nil {
   203  			return
   204  		}
   205  		syncError = p.refreshCache(timeout, client)
   206  		return
   207  	}
   208  
   209  	logger.Info("connecting to source")
   210  	if _, syncError = p.sources.Add(key, address); syncError != nil {
   211  		logger.Warn("failed to create a new source")
   212  	}
   213  
   214  	return
   215  }
   216  
   217  func (p *RegistryProvider) syncSourceState(state registrygrpc.SourceState) {
   218  	key := state.Key
   219  	logger := logrus.WithFields(logrus.Fields{
   220  		"action": "sync source",
   221  		"source": key,
   222  		"state":  state.State,
   223  	})
   224  	logger.Debug("source state changed")
   225  
   226  	timeout, cancel := context.WithTimeout(context.Background(), cacheTimeout)
   227  	defer cancel()
   228  
   229  	var err error
   230  	switch state.State {
   231  	case connectivity.Ready:
   232  		var client *registryClient
   233  		client, err = p.registryClient(key)
   234  		if err == nil {
   235  			err = p.refreshCache(timeout, client)
   236  		}
   237  	case connectivity.TransientFailure, connectivity.Shutdown:
   238  		err = p.gcPackages(key, nil)
   239  	default:
   240  		logger.Debug("inert source state, skipping cache update")
   241  	}
   242  
   243  	if err != nil {
   244  		logger.WithError(err).Warn("failed to update cache")
   245  	}
   246  }
   247  
   248  func (p *RegistryProvider) registryClient(key registry.CatalogKey) (client *registryClient, err error) {
   249  	source := p.sources.Get(key)
   250  	if source == nil {
   251  		err = fmt.Errorf("missing source for catalog %s", key)
   252  		return
   253  	}
   254  
   255  	conn := source.Conn
   256  	if conn == nil {
   257  		err = fmt.Errorf("missing grpc connection for source %s", key)
   258  		return
   259  	}
   260  
   261  	var catsrc *operatorsv1alpha1.CatalogSource
   262  	catsrc, err = p.catsrcLister.CatalogSources(key.Namespace).Get(key.Name)
   263  	if err != nil {
   264  		return
   265  	}
   266  
   267  	client = newRegistryClient(catsrc, conn)
   268  	return
   269  }
   270  
   271  func getOperatorDeprecation(in *api.Deprecation) *operators.Deprecation {
   272  	if in == nil {
   273  		return nil
   274  	}
   275  	return &operators.Deprecation{
   276  		Message: in.Message,
   277  	}
   278  }
   279  
   280  func (p *RegistryProvider) refreshCache(ctx context.Context, client *registryClient) error {
   281  	key, err := client.key()
   282  	if err != nil {
   283  		return err
   284  	}
   285  
   286  	logger := logrus.WithFields(logrus.Fields{
   287  		"action": "refresh cache",
   288  		"source": key,
   289  	})
   290  
   291  	bundleStream, err := client.ListBundles(ctx, &api.ListBundlesRequest{})
   292  	if err != nil {
   293  		logger.WithField("err", err.Error()).Warnf("error getting bundle stream")
   294  		return nil
   295  	}
   296  
   297  	bundles := map[string]map[string][]operators.ChannelEntry{}
   298  
   299  	for {
   300  		bundle, err := bundleStream.Recv()
   301  		if err == io.EOF {
   302  			break
   303  		}
   304  		if err != nil {
   305  			logger.WithField("err", err.Error()).Warnf("error getting bundle data")
   306  			break
   307  		}
   308  		if isDeprecated(bundle) {
   309  			continue
   310  		}
   311  		if _, ok := bundles[bundle.PackageName]; !ok {
   312  			bundles[bundle.PackageName] = map[string][]operators.ChannelEntry{}
   313  		}
   314  
   315  		bundles[bundle.PackageName][bundle.ChannelName] = append(bundles[bundle.PackageName][bundle.ChannelName], operators.ChannelEntry{
   316  			Name:        bundle.CsvName,
   317  			Version:     bundle.Version,
   318  			Deprecation: getOperatorDeprecation(bundle.Deprecation),
   319  		})
   320  	}
   321  
   322  	stream, err := client.ListPackages(ctx, &api.ListPackageRequest{})
   323  	if err != nil {
   324  		logger.WithField("err", err.Error()).Warnf("error getting package stream")
   325  		return nil
   326  	}
   327  
   328  	for pkgName := range bundles {
   329  		for chName := range bundles[pkgName] {
   330  			sort.Slice(bundles[pkgName][chName], func(i, j int) bool {
   331  				iV, err := semver.Parse(bundles[pkgName][chName][i].Version)
   332  				if err != nil {
   333  					iV = semver.Version{}
   334  				}
   335  				jV, err := semver.Parse(bundles[pkgName][chName][j].Version)
   336  				if err != nil {
   337  					jV = semver.Version{}
   338  				}
   339  				return iV.GT(jV)
   340  			})
   341  		}
   342  	}
   343  
   344  	var (
   345  		added = map[string]struct{}{}
   346  		mu    sync.Mutex
   347  		wg    sync.WaitGroup
   348  	)
   349  	for {
   350  		pkgName, err := stream.Recv()
   351  		if err == io.EOF {
   352  			break
   353  		}
   354  		if err != nil {
   355  			logger.WithField("err", err.Error()).Warnf("error getting package name data")
   356  			break
   357  		}
   358  
   359  		wg.Add(1)
   360  		go func() {
   361  			defer wg.Done()
   362  			pkg, err := client.GetPackage(ctx, &api.GetPackageRequest{Name: pkgName.GetName()})
   363  			if err != nil {
   364  				logger.WithField("err", err.Error()).Warnf("eliding package: error getting package")
   365  				return
   366  			}
   367  
   368  			newPkg, err := newPackageManifest(ctx, logger, pkg, client, bundles[pkg.GetName()])
   369  			if err != nil {
   370  				logger.WithField("err", err.Error()).Warnf("eliding package: error converting to packagemanifest")
   371  				return
   372  			}
   373  
   374  			if err := p.cache.Add(newPkg); err != nil {
   375  				logger.WithField("err", err.Error()).Warnf("eliding package: failed to add to cache")
   376  				return
   377  			}
   378  
   379  			mu.Lock()
   380  			defer mu.Unlock()
   381  			added[newPkg.GetName()] = struct{}{}
   382  		}()
   383  	}
   384  
   385  	logger.Debug("caching new packages...")
   386  	wg.Wait()
   387  	logger.Debug("new packages cached")
   388  
   389  	// Garbage collect orphaned packagemanifests from the cache
   390  	return p.gcPackages(key, added)
   391  }
   392  
   393  func isDeprecated(b *api.Bundle) bool {
   394  	for _, p := range b.Properties {
   395  		if p.Type == orregistry.DeprecatedType {
   396  			return true
   397  		}
   398  	}
   399  	return false
   400  }
   401  
   402  func (p *RegistryProvider) gcPackages(key registry.CatalogKey, keep map[string]struct{}) error {
   403  	logger := logrus.WithFields(logrus.Fields{
   404  		"action": "gc cache",
   405  		"source": key.String(),
   406  	})
   407  
   408  	storedPkgKeys, err := p.cache.IndexKeys(catalogIndex, key.String())
   409  	if err != nil {
   410  		return err
   411  	}
   412  
   413  	var errs []error
   414  	for _, storedPkgKey := range storedPkgKeys {
   415  		_, _, name, _ := SplitPackageManifestKey(storedPkgKey)
   416  		if keep != nil {
   417  			if _, ok := keep[name]; ok {
   418  				continue
   419  			}
   420  		}
   421  		if err := p.cache.Delete(storedPkgKey); err != nil {
   422  			logger.WithField("pkg", name).WithError(err).Warn("failed to delete cache entry")
   423  			errs = append(errs, err)
   424  		}
   425  	}
   426  
   427  	return utilerrors.NewAggregate(errs)
   428  }
   429  
   430  func (p *RegistryProvider) catalogSourceDeleted(obj interface{}) {
   431  	catsrc, ok := obj.(metav1.Object)
   432  	if !ok {
   433  		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
   434  		if !ok {
   435  			utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
   436  			return
   437  		}
   438  
   439  		catsrc, ok = tombstone.Obj.(metav1.Object)
   440  		if !ok {
   441  			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a Namespace %#v", obj))
   442  			return
   443  		}
   444  	}
   445  
   446  	key := registry.CatalogKey{
   447  		Namespace: catsrc.GetNamespace(),
   448  		Name:      catsrc.GetName(),
   449  	}
   450  	logger := logrus.WithFields(logrus.Fields{
   451  		"action": "CatalogSource Deleted",
   452  		"source": key.String(),
   453  	})
   454  
   455  	if err := p.sources.Remove(key); err != nil {
   456  		logger.WithError(err).Warn("failed to remove source")
   457  	}
   458  
   459  	if err := p.gcPackages(key, nil); err != nil {
   460  		logger.WithError(err).Warn("failed to gc orphaned packages in cache")
   461  	}
   462  }
   463  
   464  func (p *RegistryProvider) Get(namespace, name string) (*operators.PackageManifest, error) {
   465  	logger := logrus.WithFields(logrus.Fields{
   466  		"action":    "Get PackageManifest",
   467  		"name":      name,
   468  		"namespace": namespace,
   469  	})
   470  
   471  	pkgs, err := p.List(namespace, labels.Everything())
   472  	if err != nil {
   473  		return nil, fmt.Errorf("could not list packages in namespace %s", namespace)
   474  	}
   475  
   476  	for _, pkg := range pkgs.Items {
   477  		if pkg.GetName() == name {
   478  			return &pkg, nil
   479  		}
   480  	}
   481  
   482  	logger.Info("package not found")
   483  	return nil, nil
   484  }
   485  
   486  func (p *RegistryProvider) List(namespace string, selector labels.Selector) (*operators.PackageManifestList, error) {
   487  	var pkgs []*operators.PackageManifest
   488  	if namespace == metav1.NamespaceAll {
   489  		all, err := p.pkgLister.List(selector)
   490  		if err != nil {
   491  			return nil, err
   492  		}
   493  		pkgs = append(pkgs, all...)
   494  	} else {
   495  		nsPkgs, err := p.pkgLister.PackageManifests(namespace).List(selector)
   496  		if err != nil {
   497  			return nil, err
   498  		}
   499  		pkgs = append(pkgs, nsPkgs...)
   500  
   501  		if namespace != p.globalNamespace {
   502  			globalPkgs, err := p.pkgLister.PackageManifests(p.globalNamespace).List(selector)
   503  			if err != nil {
   504  				return nil, err
   505  			}
   506  
   507  			pkgs = append(pkgs, globalPkgs...)
   508  		}
   509  	}
   510  
   511  	pkgList := &operators.PackageManifestList{}
   512  	for _, pkg := range pkgs {
   513  		out := pkg.DeepCopy()
   514  		// Set request namespace to stop k8s clients from complaining about namespace mismatch.
   515  		if namespace != metav1.NamespaceAll {
   516  			out.SetNamespace(namespace)
   517  		}
   518  		pkgList.Items = append(pkgList.Items, *out)
   519  	}
   520  
   521  	return pkgList, nil
   522  }
   523  
   524  func newPackageManifest(ctx context.Context, logger *logrus.Entry, pkg *api.Package, client *registryClient, entriesByChannel map[string][]operators.ChannelEntry) (*operators.PackageManifest, error) {
   525  	pkgChannels := pkg.GetChannels()
   526  	sort.Slice(pkgChannels, func(i, j int) bool {
   527  		return pkgChannels[i].Name < pkgChannels[j].Name
   528  	})
   529  	catsrc := client.catsrc
   530  	manifest := &operators.PackageManifest{
   531  		ObjectMeta: metav1.ObjectMeta{
   532  			Name:      pkg.GetName(),
   533  			Namespace: catsrc.GetNamespace(),
   534  			Labels: utillabels.CloneAndAddLabel(
   535  				utillabels.CloneAndAddLabel(catsrc.GetLabels(),
   536  					"catalog", catsrc.GetName()), "catalog-namespace", catsrc.GetNamespace()),
   537  			CreationTimestamp: catsrc.GetCreationTimestamp(),
   538  		},
   539  		Status: operators.PackageManifestStatus{
   540  			CatalogSource:            catsrc.GetName(),
   541  			CatalogSourceDisplayName: catsrc.Spec.DisplayName,
   542  			CatalogSourcePublisher:   catsrc.Spec.Publisher,
   543  			CatalogSourceNamespace:   catsrc.GetNamespace(),
   544  			PackageName:              pkg.Name,
   545  			DefaultChannel:           pkg.GetDefaultChannelName(),
   546  			Deprecation:              getOperatorDeprecation(pkg.Deprecation),
   547  		},
   548  	}
   549  
   550  	var (
   551  		providerSet   bool
   552  		defaultElided bool
   553  		defaultCsv    *operatorsv1alpha1.ClusterServiceVersion
   554  	)
   555  	for _, pkgChannel := range pkgChannels {
   556  		// TODO: replace with non-deprecated API (e.g. client.GetBundle())
   557  		// nolint:staticcheck
   558  		bundle, err := client.GetBundleForChannel(ctx, &api.GetBundleInChannelRequest{PkgName: pkg.GetName(), ChannelName: pkgChannel.GetName()})
   559  		if err != nil {
   560  			logger.WithError(err).WithField("channel", pkgChannel.GetName()).Warn("error getting bundle, eliding channel")
   561  			defaultElided = defaultElided || pkgChannel.Name == manifest.Status.DefaultChannel
   562  			continue
   563  		}
   564  
   565  		csv := operatorsv1alpha1.ClusterServiceVersion{}
   566  		err = json.Unmarshal([]byte(bundle.GetCsvJson()), &csv)
   567  		if err != nil {
   568  			logger.WithError(err).WithField("channel", pkgChannel.GetName()).Warn("error unmarshaling csv, eliding channel")
   569  			defaultElided = defaultElided || pkgChannel.Name == manifest.Status.DefaultChannel
   570  			continue
   571  		}
   572  		if defaultCsv == nil || pkgChannel.GetName() == manifest.Status.DefaultChannel {
   573  			defaultCsv = &csv
   574  		}
   575  		manifest.Status.Channels = append(manifest.Status.Channels, operators.PackageChannel{
   576  			Name:           pkgChannel.GetName(),
   577  			CurrentCSV:     csv.GetName(),
   578  			CurrentCSVDesc: operators.CreateCSVDescription(&csv, bundle.GetCsvJson()),
   579  			Entries:        entriesByChannel[pkgChannel.GetName()],
   580  			Deprecation:    getOperatorDeprecation(pkgChannel.Deprecation),
   581  		})
   582  
   583  		if manifest.Status.DefaultChannel != "" && pkgChannel.GetName() == manifest.Status.DefaultChannel || !providerSet {
   584  			manifest.Status.Provider = operators.AppLink{
   585  				Name: csv.Spec.Provider.Name,
   586  				URL:  csv.Spec.Provider.URL,
   587  			}
   588  			manifest.ObjectMeta.Labels["provider"] = manifest.Status.Provider.Name
   589  			manifest.ObjectMeta.Labels["provider-url"] = manifest.Status.Provider.URL
   590  			providerSet = true
   591  		}
   592  	}
   593  
   594  	if len(manifest.Status.Channels) == 0 {
   595  		return nil, fmt.Errorf("packagemanifest has no valid channels")
   596  	}
   597  
   598  	if defaultElided {
   599  		logger.Warn("default channel elided, setting as first in packagemanifest")
   600  		manifest.Status.DefaultChannel = manifest.Status.Channels[0].Name
   601  	}
   602  	manifestLabels := manifest.GetLabels()
   603  	for k, v := range defaultCsv.GetLabels() {
   604  		manifestLabels[k] = v
   605  	}
   606  	setDefaultOsArchLabels(manifestLabels)
   607  	manifest.SetLabels(manifestLabels)
   608  	return manifest, nil
   609  }