Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var CreateCommand = cli.Command{ Name: "create", Usage: "create SOCI index", ArgsUsage: "[flags] <image_ref>", Flags: append( internal.PlatformFlags, cli.Int64Flag{ Name: spanSizeFlag, Usage: "Span size that soci index uses to segment layer data. Default is 4 MiB", Value: 1 << 22, }, cli.Int64Flag{ Name: minLayerSizeFlag, Usage: "Minimum layer size to build zTOC for. Smaller layers won't have zTOC and not lazy pulled. Default is 10 MiB.", Value: 10 << 20, }, cli.StringSliceFlag{ Name: optimizationFlag, Usage: fmt.Sprintf("(Experimental) Enable optional optimizations. Valid values are %v", soci.Optimizations), }, ), Action: func(cliContext *cli.Context) error { srcRef := cliContext.Args().Get(0) if srcRef == "" { return errors.New("source image needs to be specified") } var optimizations []soci.Optimization for _, o := range cliContext.StringSlice(optimizationFlag) { optimization, err := soci.ParseOptimization(o) if err != nil { return err } optimizations = append(optimizations, optimization) } client, ctx, cancel, err := internal.NewClient(cliContext) if err != nil { return err } defer cancel() cs := client.ContentStore() is := client.ImageService() srcImg, err := is.Get(ctx, srcRef) if err != nil { return err } spanSize := cliContext.Int64(spanSizeFlag) minLayerSize := cliContext.Int64(minLayerSizeFlag) if _, err := os.Stat(config.SociSnapshotterRootPath); os.IsNotExist(err) { if err = os.Mkdir(config.SociSnapshotterRootPath, 0711); err != nil { return err } } else if err != nil { return err } ctx, blobStore, err := store.NewContentStore(ctx, internal.ContentStoreOptions(cliContext)...) if err != nil { return err } ps, err := internal.GetPlatforms(ctx, cliContext, srcImg, cs) if err != nil { return err } artifactsDb, err := soci.NewDB(soci.ArtifactsDbPath()) if err != nil { return err } builderOpts := []soci.BuildOption{ soci.WithMinLayerSize(minLayerSize), soci.WithSpanSize(spanSize), soci.WithBuildToolIdentifier(buildToolIdentifier), soci.WithOptimizations(optimizations), } for _, plat := range ps { builder, err := soci.NewIndexBuilder(cs, blobStore, artifactsDb, append(builderOpts, soci.WithPlatform(plat))...) if err != nil { return err } _, err = builder.Build(ctx, srcImg) if err != nil { return err } } return nil }, }
CreateCommand creates SOCI index for an image Output of this command is SOCI layers and SOCI index stored in a local directory SOCI layer is named as <image-layer-digest>.soci.layer SOCI index is named as <image-manifest-digest>.soci.index
View Source
var PushCommand = cli.Command{ Name: "push", Usage: "push SOCI artifacts to a registry", ArgsUsage: "[flags] <ref>", Description: `Push SOCI artifacts to a registry by image reference. If multiple soci indices exist for the given image, the most recent one will be pushed. After pushing the soci artifacts, they should be available in the registry. Soci artifacts will be pushed only if they are available in the snapshotter's local content store. `, Flags: append(append(append( internal.RegistryFlags, internal.SnapshotterFlags...), internal.PlatformFlags...), internal.ExistingIndexFlag, cli.Uint64Flag{ Name: maxConcurrentUploadsFlag, Usage: fmt.Sprintf("Max concurrent uploads. Default is %d", defaultMaxConcurrentUploads), Value: defaultMaxConcurrentUploads, }, cli.BoolFlag{ Name: "quiet, q", Usage: "quiet mode", }, ), Action: func(cliContext *cli.Context) error { ref := cliContext.Args().First() quiet := cliContext.Bool("quiet") if ref == "" { return fmt.Errorf("please provide an image reference to push") } client, ctx, cancel, err := internal.NewClient(cliContext) if err != nil { return err } defer cancel() cs := client.ContentStore() is := client.ImageService() img, err := is.Get(ctx, ref) if err != nil { return err } ps, err := internal.GetPlatforms(ctx, cliContext, img, cs) if err != nil { return err } artifactsDb, err := soci.NewDB(soci.ArtifactsDbPath()) if err != nil { return err } refspec, err := reference.Parse(ref) if err != nil { return err } dst, err := remote.NewRepository(refspec.Locator) if err != nil { return err } authClient := auth.DefaultClient var username string var secret string if cliContext.IsSet("user") { username = cliContext.String("user") if i := strings.IndexByte(username, ':'); i > 0 { secret = username[i+1:] username = username[0:i] } } else { cf := dockercliconfig.LoadDefaultConfigFile(io.Discard) if cf.ContainsAuth() { if ac, err := cf.GetAuthConfig(refspec.Hostname()); err == nil { username = ac.Username secret = ac.Password } } } authClient.Credential = func(_ context.Context, host string) (auth.Credential, error) { return auth.Credential{ Username: username, Password: secret, }, nil } ctx, src, err := store.NewContentStore(ctx, internal.ContentStoreOptions(cliContext)...) if err != nil { return fmt.Errorf("cannot create local content store: %w", err) } dst.Client = authClient dst.PlainHTTP = cliContext.Bool("plain-http") debug := cliContext.GlobalBool("debug") if debug { dst.Client = &debugClient{client: authClient} } else { dst.Client = authClient } existingIndexOption := cliContext.String(internal.ExistingIndexFlagName) if !internal.SupportedArg(existingIndexOption, internal.SupportedExistingIndexOptions) { return fmt.Errorf("unexpected value for flag %s: %s, expected types %v", internal.ExistingIndexFlagName, existingIndexOption, internal.SupportedExistingIndexOptions) } options := oraslib.DefaultCopyGraphOptions if value := cliContext.Uint64(maxConcurrentUploadsFlag); value == 0 { options.Concurrency = defaultMaxConcurrentUploads } else if value > math.MaxInt { if !quiet { fmt.Printf("warning: overflow for setting --%s=%d; defaulting to %d", maxConcurrentUploadsFlag, value, defaultMaxConcurrentUploads) } options.Concurrency = defaultMaxConcurrentUploads } else { options.Concurrency = int(value) } options.PreCopy = func(_ context.Context, desc ocispec.Descriptor) error { if !quiet { fmt.Printf("pushing artifact with digest: %v\n", desc.Digest) } return nil } options.PostCopy = func(_ context.Context, desc ocispec.Descriptor) error { if !quiet { fmt.Printf("successfully pushed artifact with digest: %v\n", desc.Digest) } return nil } options.OnCopySkipped = func(ctx context.Context, desc ocispec.Descriptor) error { if !quiet { fmt.Printf("skipped artifact with digest: %v\n", desc.Digest) } return nil } for _, platform := range ps { indexDescriptors, imgManifestDesc, err := soci.GetIndexDescriptorCollection(ctx, cs, artifactsDb, img, []ocispec.Platform{platform}) if err != nil { return err } if len(indexDescriptors) == 0 { return fmt.Errorf("could not find any soci indices to push") } sort.Slice(indexDescriptors, func(i, j int) bool { return indexDescriptors[i].CreatedAt.Before(indexDescriptors[j].CreatedAt) }) indexDesc := indexDescriptors[len(indexDescriptors)-1] if existingIndexOption != internal.Allow { if !quiet { fmt.Println("checking if a soci index already exists in remote repository...") } client := fs.NewOCIArtifactClient(dst) referrers, err := client.AllReferrers(ctx, ocispec.Descriptor{Digest: imgManifestDesc.Digest}) if err != nil && !errors.Is(err, fs.ErrNoReferrers) { return fmt.Errorf("failed to fetch list of referrers: %w", err) } if len(referrers) > 0 { var foundMessage string if len(referrers) > 1 { foundMessage = "multiple soci indices found in remote repository" } else { foundMessage = fmt.Sprintf("soci index found in remote repository with digest: %s", referrers[0].Digest.String()) } switch existingIndexOption { case internal.Skip: if !quiet { fmt.Printf("%s: skipping pushing artifacts for image manifest: %s\n", foundMessage, imgManifestDesc.Digest.String()) } continue case internal.Warn: fmt.Printf("[WARN] %s: pushing index anyway\n", foundMessage) } } } if quiet { fmt.Println(indexDesc.Digest.String()) } else { fmt.Printf("pushing soci index with digest: %v\n", indexDesc.Digest) } err = oraslib.CopyGraph(context.Background(), src, dst, indexDesc.Descriptor, options) if err != nil { return fmt.Errorf("error pushing graph to remote: %w", err) } } return nil }, }
PushCommand is a command to push an image artifacts from local content store to the remote repository
View Source
var RebuildDBCommand = cli.Command{ Name: "rebuild-db", Usage: "rebuilds the artifacts database", UsageText: ` soci [global options] rebuild-db Use after pulling an image to discover SOCI indices/ztocs or after "index rm" when using the containerd content store to clear the database of removed zTOCs. `, Action: func(cliContext *cli.Context) error { client, ctx, cancel, err := internal.NewClient(cliContext) if err != nil { return err } defer cancel() containerdContentStore := client.ContentStore() artifactsDb, err := soci.NewDB(soci.ArtifactsDbPath()) if err != nil { return err } ctx, blobStore, err := store.NewContentStore(ctx, internal.ContentStoreOptions(cliContext)...) if err != nil { return err } contentStorePath, err := store.GetContentStorePath(store.ContentStoreType(cliContext.GlobalString("content-store"))) if err != nil { return err } blobStorePath := filepath.Join(contentStorePath, "blobs") return artifactsDb.SyncWithLocalStore(ctx, blobStore, blobStorePath, containerdContentStore) }, }
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.