Skip to content

Commit

Permalink
Hack to allow rm to work with oras v2 until oras-project/oras-go#454
Browse files Browse the repository at this point in the history
Signed-off-by: carabasdaniel <[email protected]>
  • Loading branch information
carabasdaniel committed Mar 13, 2023
1 parent 65b512f commit 83a73f9
Showing 1 changed file with 89 additions and 10 deletions.
99 changes: 89 additions & 10 deletions pkg/app/rm.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package app

import (
"encoding/json"
"os"
"path/filepath"
"strings"

"github.com/opcr-io/policy/pkg/oci"
"github.com/opcr-io/policy/pkg/parser"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"oras.land/oras-go/pkg/content"
)

func (c *PolicyApp) Rm(existingRef string, force bool) error {
Expand All @@ -30,35 +36,108 @@ func (c *PolicyApp) Rm(existingRef string, force bool) error {
return nil
}

ociStore, err := content.NewOCI(c.Configuration.PoliciesRoot())
ociClient, err := oci.NewOCI(c.Context, c.Logger, c.getHosts, c.Configuration.PoliciesRoot())
if err != nil {
return err
}
err = ociStore.LoadIndex()

existingRefs, err := ociClient.ListReferences()
if err != nil {
return err
}

existingRefs := ociStore.ListReferences()

_, ok := existingRefs[existingRefParsed]
ref, ok := existingRefs[existingRefParsed]
if !ok {
return errors.Errorf("ref [%s] not found in the local store", existingRef)
}
// attach ref name annotation for comparisson.
ref.Annotations = make(map[string]string)
ref.Annotations[ocispec.AnnotationRefName] = existingRefParsed

ociStore.DeleteReference(existingRefParsed)
err = c.removeFromIndex(ref)
if err != nil {
return err
}

// Reload ociClient with refreshed index to update reference list.
ociClient, err = oci.NewOCI(c.Context, c.Logger, c.getHosts, c.Configuration.PoliciesRoot())
if err != nil {
return err
}

// TODO: if there are no references left to the policy, perhaps delete the descriptor?
// or implement a cleanup command.
updatedRefs, err := ociClient.ListReferences()
if err != nil {
return err
}
// Check if existing images use same digest.
removeBlob := true
for _, v := range updatedRefs {
if v.Digest == ref.Digest {
removeBlob = false
break
}
}
// only remove the blob if not used by another reference.
if removeBlob {
// Hack to remove the existing digest until ocistore deleter is implemented
// https://github.com/oras-project/oras-go/issues/454
digestPath := filepath.Join(strings.Split(ref.Digest.String(), ":")...)
blob := filepath.Join(c.Configuration.PoliciesRoot(), "blobs", digestPath)
err = os.Remove(blob)
if err != nil {
return err
}
}

c.UI.Normal().
WithStringValue("reference", existingRef).
Msg("Removed reference.")

err = ociStore.SaveIndex()
return nil
}

func (c *PolicyApp) removeFromIndex(ref ocispec.Descriptor) error {

type index struct {
Version int `json:"schemaVersion"`
Manifests []ocispec.Descriptor `json:"manifests"`
}

var localIndex index
indexPath := filepath.Join(c.Configuration.PoliciesRoot(), "index.json")
indexBytes, err := os.ReadFile(indexPath)
if err != nil {
return err
}

err = json.Unmarshal(indexBytes, &localIndex)
if err != nil {
return err
}

localIndex.Manifests = removeFromManifests(localIndex.Manifests, ref)

newIndexBytes, err := json.Marshal(localIndex)
if err != nil {
return err
}

err = os.WriteFile(indexPath, newIndexBytes, 0664)
if err != nil {
return err
}
return nil
}

func removeFromManifests(manifests []ocispec.Descriptor, ref ocispec.Descriptor) []ocispec.Descriptor {
newarray := make([]ocispec.Descriptor, len(manifests)-1)
k := 0
for i := 0; i < len(manifests); i++ {
if manifests[i].Digest == ref.Digest && manifests[i].Annotations[ocispec.AnnotationRefName] == ref.Annotations[ocispec.AnnotationRefName] {
continue
}
newarray[k] = manifests[i]
k++
}
return newarray
}

0 comments on commit 83a73f9

Please sign in to comment.