mirror of
https://github.com/containers/skopeo.git
synced 2025-05-04 22:16:43 +00:00
Card container_security_113 - Delete image support
Add support to mark images for deletion from repository Requires: * V2 API and schema * registry configured to allow deletes * run registry garbage collection to free up disk space Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
parent
0ff261802b
commit
f3efa063e3
cmd/skopeo
directory
docker
man1
openshift
types
27
cmd/skopeo/delete.go
Normal file
27
cmd/skopeo/delete.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func deleteHandler(context *cli.Context) {
|
||||||
|
if len(context.Args()) != 1 {
|
||||||
|
logrus.Fatal("Usage: delete imageReference")
|
||||||
|
}
|
||||||
|
|
||||||
|
image, err := parseImageSource(context, context.Args()[0])
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := image.Delete(); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleteCmd = cli.Command{
|
||||||
|
Name: "delete",
|
||||||
|
Usage: "Delete given image",
|
||||||
|
Action: deleteHandler,
|
||||||
|
}
|
@ -63,6 +63,7 @@ func main() {
|
|||||||
copyCmd,
|
copyCmd,
|
||||||
inspectCmd,
|
inspectCmd,
|
||||||
layersCmd,
|
layersCmd,
|
||||||
|
deleteCmd,
|
||||||
standaloneSignCmd,
|
standaloneSignCmd,
|
||||||
standaloneVerifyCmd,
|
standaloneVerifyCmd,
|
||||||
}
|
}
|
||||||
|
@ -111,3 +111,7 @@ func (s *dirImageSource) GetSignatures() ([][]byte, error) {
|
|||||||
}
|
}
|
||||||
return signatures, nil
|
return signatures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *dirImageSource) Delete() error {
|
||||||
|
return fmt.Errorf("directory#dirImageSource.Delete() not implmented")
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/projectatomic/skopeo/docker/utils"
|
||||||
"github.com/projectatomic/skopeo/reference"
|
"github.com/projectatomic/skopeo/reference"
|
||||||
"github.com/projectatomic/skopeo/types"
|
"github.com/projectatomic/skopeo/types"
|
||||||
)
|
)
|
||||||
@ -94,3 +95,51 @@ func (s *dockerImageSource) GetLayer(digest string) (io.ReadCloser, error) {
|
|||||||
func (s *dockerImageSource) GetSignatures() ([][]byte, error) {
|
func (s *dockerImageSource) GetSignatures() ([][]byte, error) {
|
||||||
return [][]byte{}, nil
|
return [][]byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *dockerImageSource) Delete() error {
|
||||||
|
var body []byte
|
||||||
|
|
||||||
|
// When retrieving the digest from a registry >= 2.3 use the following header:
|
||||||
|
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
|
||||||
|
headers := make(map[string][]string)
|
||||||
|
headers["Accept"] = []string{utils.DockerV2Schema2MIMEType}
|
||||||
|
|
||||||
|
getURL := fmt.Sprintf(manifestURL, s.ref.RemoteName(), s.tag)
|
||||||
|
get, err := s.c.makeRequest("GET", getURL, headers, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer get.Body.Close()
|
||||||
|
body, err = ioutil.ReadAll(get.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch get.StatusCode {
|
||||||
|
case http.StatusOK:
|
||||||
|
case http.StatusNotFound:
|
||||||
|
return fmt.Errorf("Unable to delete %v. Image may not exist or is not stored with a v2 Schema in a v2 registry.", s.ref)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Failed to delete %v: %v (%v)", s.ref, body, get.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
digest := get.Header.Get("Docker-Content-Digest")
|
||||||
|
deleteURL := fmt.Sprintf(manifestURL, s.ref.RemoteName(), digest)
|
||||||
|
|
||||||
|
// When retrieving the digest from a registry >= 2.3 use the following header:
|
||||||
|
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
|
||||||
|
delete, err := s.c.makeRequest("DELETE", deleteURL, headers, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer delete.Body.Close()
|
||||||
|
|
||||||
|
body, err = ioutil.ReadAll(delete.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if delete.StatusCode != http.StatusAccepted {
|
||||||
|
return fmt.Errorf("Failed to delete %v: %v (%v)", deleteURL, body, delete.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -10,6 +10,8 @@ skopeo \(em Inspect Docker images and repositories on registries
|
|||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
\fBskopeo copy\fR [\fB--sign-by=\fRkey-ID] source-location destination-location
|
\fBskopeo copy\fR [\fB--sign-by=\fRkey-ID] source-location destination-location
|
||||||
.PP
|
.PP
|
||||||
|
\fBskopeo delete\fR source-location
|
||||||
|
.PP
|
||||||
\fBskopeo inspect\fR image-name [\fB--raw\fR]
|
\fBskopeo inspect\fR image-name [\fB--raw\fR]
|
||||||
.PP
|
.PP
|
||||||
\fBskopeo layers\fR image-name
|
\fBskopeo layers\fR image-name
|
||||||
@ -54,12 +56,22 @@ Copy an image (manifest, filesystem layers, signatures) from one location to ano
|
|||||||
.B source-location
|
.B source-location
|
||||||
and
|
and
|
||||||
.B destination-location
|
.B destination-location
|
||||||
can be \fBdocker://\fRdocker-reference, \fBdir:\fRlocal-path, or \fBatomic:\fRimagestream-name\fB:\fRtag .
|
can be \fB\%docker://\fRdocker-reference, \fBdir:\fRlocal-path, or \fBatomic:\fRimagestream-name\fB:\fRtag .
|
||||||
.sp
|
.sp
|
||||||
\fB\-\-sign\-by=\fRkey-id
|
\fB\-\-sign\-by=\fRkey-id
|
||||||
Add a signature by the specified key ID for image name corresponding to \fBdestination-location\fR.
|
Add a signature by the specified key ID for image name corresponding to \fBdestination-location\fR.
|
||||||
Existing signatures, if any, are preserved as well.
|
Existing signatures, if any, are preserved as well.
|
||||||
.TP
|
.TP
|
||||||
|
.B delete
|
||||||
|
Mark an image for deletion. You must then run docker registry garabage collection to recover the disk space. E.g.,
|
||||||
|
.sp
|
||||||
|
\fBdocker exec -it registry bin/registry \\
|
||||||
|
.br
|
||||||
|
garbage-collect /etc/docker/registry/config.yml\fR
|
||||||
|
.sp 2
|
||||||
|
Additionally, the registry must allow deletions by setting \fB\%REGISTRY_STORAGE_DELETE_ENABLED=true\fR
|
||||||
|
for the registry daemon.
|
||||||
|
.TP
|
||||||
.B inspect
|
.B inspect
|
||||||
Return low-level information on images in a registry
|
Return low-level information on images in a registry
|
||||||
.sp
|
.sp
|
||||||
|
@ -396,3 +396,7 @@ type status struct {
|
|||||||
// Details *StatusDetails `json:"details,omitempty"`
|
// Details *StatusDetails `json:"details,omitempty"`
|
||||||
Code int32 `json:"code,omitempty"`
|
Code int32 `json:"code,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *openshiftImageSource) Delete() error {
|
||||||
|
return fmt.Errorf("openshift#openshiftImageSource.Delete() not implmented")
|
||||||
|
}
|
||||||
|
@ -33,6 +33,8 @@ type ImageSource interface {
|
|||||||
GetLayer(digest string) (io.ReadCloser, error)
|
GetLayer(digest string) (io.ReadCloser, error)
|
||||||
// GetSignatures returns the image's signatures. It may use a remote (= slow) service.
|
// GetSignatures returns the image's signatures. It may use a remote (= slow) service.
|
||||||
GetSignatures() ([][]byte, error)
|
GetSignatures() ([][]byte, error)
|
||||||
|
// Delete image from registry, if operation is supported
|
||||||
|
Delete() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageDestination is a service, possibly remote (= slow), to store components of a single image.
|
// ImageDestination is a service, possibly remote (= slow), to store components of a single image.
|
||||||
|
Loading…
Reference in New Issue
Block a user