Remove fronting mux router and use route and auth extensions added
upstream in registry.
Move admin registry handlers into pkg/dockerregistry/server.
Rename --older-than to --keep-younger-than and make it a time.Duration.
| ... | ... |
@@ -3,7 +3,6 @@ package dockerregistry |
| 3 | 3 |
import ( |
| 4 | 4 |
"crypto/tls" |
| 5 | 5 |
"crypto/x509" |
| 6 |
- "encoding/json" |
|
| 7 | 6 |
"fmt" |
| 8 | 7 |
"io" |
| 9 | 8 |
"io/ioutil" |
| ... | ... |
@@ -13,174 +12,15 @@ import ( |
| 13 | 13 |
log "github.com/Sirupsen/logrus" |
| 14 | 14 |
"github.com/docker/distribution/configuration" |
| 15 | 15 |
"github.com/docker/distribution/context" |
| 16 |
- "github.com/docker/distribution/health" |
|
| 16 |
+ "github.com/docker/distribution/registry/auth" |
|
| 17 | 17 |
"github.com/docker/distribution/registry/handlers" |
| 18 | 18 |
_ "github.com/docker/distribution/registry/storage/driver/filesystem" |
| 19 | 19 |
_ "github.com/docker/distribution/registry/storage/driver/s3" |
| 20 | 20 |
"github.com/docker/distribution/version" |
| 21 | 21 |
gorillahandlers "github.com/gorilla/handlers" |
| 22 |
- "github.com/gorilla/mux" |
|
| 23 |
- _ "github.com/openshift/origin/pkg/dockerregistry/server" |
|
| 22 |
+ "github.com/openshift/origin/pkg/dockerregistry/server" |
|
| 24 | 23 |
) |
| 25 | 24 |
|
| 26 |
-func newOpenShiftHandler(app *handlers.App) http.Handler {
|
|
| 27 |
- router := mux.NewRouter() |
|
| 28 |
- router.HandleFunc("/healthz", health.StatusHandler)
|
|
| 29 |
- // TODO add https scheme |
|
| 30 |
- router.HandleFunc("/admin/layers", deleteLayerFunc(app)).Methods("DELETE")
|
|
| 31 |
- //router.HandleFunc("/admin/manifests", deleteManifestFunc(app)).Methods("DELETE")
|
|
| 32 |
- // delegate to the registry if it's not 1 of the OpenShift routes |
|
| 33 |
- router.NotFoundHandler = app |
|
| 34 |
- |
|
| 35 |
- return router |
|
| 36 |
-} |
|
| 37 |
- |
|
| 38 |
-// DeleteLayersRequest is a mapping from layers to the image repositories that |
|
| 39 |
-// reference them. Below is a sample request: |
|
| 40 |
-// |
|
| 41 |
-// {
|
|
| 42 |
-// "layer1": ["repo1", "repo2"], |
|
| 43 |
-// "layer2": ["repo1", "repo3"], |
|
| 44 |
-// ... |
|
| 45 |
-// } |
|
| 46 |
-type DeleteLayersRequest map[string][]string |
|
| 47 |
- |
|
| 48 |
-// AddLayer adds a layer to the request if it doesn't already exist. |
|
| 49 |
-func (r DeleteLayersRequest) AddLayer(layer string) {
|
|
| 50 |
- if _, ok := r[layer]; !ok {
|
|
| 51 |
- r[layer] = []string{}
|
|
| 52 |
- } |
|
| 53 |
-} |
|
| 54 |
- |
|
| 55 |
-// AddStream adds an image stream reference to the layer. |
|
| 56 |
-func (r DeleteLayersRequest) AddStream(layer, stream string) {
|
|
| 57 |
- r[layer] = append(r[layer], stream) |
|
| 58 |
-} |
|
| 59 |
- |
|
| 60 |
-type DeleteLayersResponse struct {
|
|
| 61 |
- Result string |
|
| 62 |
- Errors map[string][]string |
|
| 63 |
-} |
|
| 64 |
- |
|
| 65 |
-// deleteLayerFunc returns an http.HandlerFunc that is able to fully delete a |
|
| 66 |
-// layer from storage. |
|
| 67 |
-func deleteLayerFunc(app *handlers.App) http.HandlerFunc {
|
|
| 68 |
- return func(w http.ResponseWriter, req *http.Request) {
|
|
| 69 |
- defer req.Body.Close() |
|
| 70 |
- log.Infof("deleteLayerFunc invoked")
|
|
| 71 |
- |
|
| 72 |
- //TODO verify auth |
|
| 73 |
- |
|
| 74 |
- body, err := ioutil.ReadAll(req.Body) |
|
| 75 |
- if err != nil {
|
|
| 76 |
- //TODO |
|
| 77 |
- log.Errorf("Error reading body: %v", err)
|
|
| 78 |
- w.WriteHeader(http.StatusInternalServerError) |
|
| 79 |
- return |
|
| 80 |
- } |
|
| 81 |
- |
|
| 82 |
- deletions := DeleteLayersRequest{}
|
|
| 83 |
- err = json.Unmarshal(body, &deletions) |
|
| 84 |
- if err != nil {
|
|
| 85 |
- //TODO |
|
| 86 |
- log.Errorf("Error unmarshaling body: %v", err)
|
|
| 87 |
- w.WriteHeader(http.StatusInternalServerError) |
|
| 88 |
- return |
|
| 89 |
- } |
|
| 90 |
- |
|
| 91 |
- adminService := app.Registry().AdminService() |
|
| 92 |
- errs := map[string][]error{}
|
|
| 93 |
- for layer, repos := range deletions {
|
|
| 94 |
- log.Infof("Deleting layer=%q, repos=%v", layer, repos)
|
|
| 95 |
- errs[layer] = adminService.DeleteLayer(layer, repos) |
|
| 96 |
- } |
|
| 97 |
- |
|
| 98 |
- log.Infof("errs=%v", errs)
|
|
| 99 |
- |
|
| 100 |
- var result string |
|
| 101 |
- switch len(errs) {
|
|
| 102 |
- case 0: |
|
| 103 |
- result = "success" |
|
| 104 |
- default: |
|
| 105 |
- result = "failure" |
|
| 106 |
- } |
|
| 107 |
- |
|
| 108 |
- response := DeleteLayersResponse{
|
|
| 109 |
- Result: result, |
|
| 110 |
- Errors: map[string][]string{},
|
|
| 111 |
- } |
|
| 112 |
- |
|
| 113 |
- for layer, layerErrors := range errs {
|
|
| 114 |
- response.Errors[layer] = []string{}
|
|
| 115 |
- for _, err := range layerErrors {
|
|
| 116 |
- response.Errors[layer] = append(response.Errors[layer], err.Error()) |
|
| 117 |
- } |
|
| 118 |
- } |
|
| 119 |
- |
|
| 120 |
- buf, err := json.Marshal(&response) |
|
| 121 |
- if err != nil {
|
|
| 122 |
- w.Write([]byte(fmt.Sprintf("Error marshaling response: %v", err)))
|
|
| 123 |
- w.WriteHeader(http.StatusInternalServerError) |
|
| 124 |
- return |
|
| 125 |
- } |
|
| 126 |
- |
|
| 127 |
- w.Write(buf) |
|
| 128 |
- w.WriteHeader(http.StatusOK) |
|
| 129 |
- } |
|
| 130 |
-} |
|
| 131 |
- |
|
| 132 |
-/* |
|
| 133 |
-type DeleteManifestsRequest map[string][]string |
|
| 134 |
- |
|
| 135 |
-func (r *DeleteManifestsRequest) AddManifest(revision string) {
|
|
| 136 |
- if _, ok := r[revision]; !ok {
|
|
| 137 |
- r[revision] = []string{}
|
|
| 138 |
- } |
|
| 139 |
-} |
|
| 140 |
- |
|
| 141 |
-func (r *DeleteManifestsRequest) AddStream(revision, stream string) {
|
|
| 142 |
- r[revision] = append(r[revision], stream) |
|
| 143 |
-} |
|
| 144 |
- |
|
| 145 |
-func deleteManifestsFunc(app *handlers.App) http.HandlerFunc {
|
|
| 146 |
- return func(w http.ResponseWriter, req *http.Request) {
|
|
| 147 |
- defer req.Body.Close() |
|
| 148 |
- |
|
| 149 |
- //TODO verify auth |
|
| 150 |
- |
|
| 151 |
- body, err := ioutil.ReadAll(req.Body) |
|
| 152 |
- if err != nil {
|
|
| 153 |
- //TODO |
|
| 154 |
- log.Errorf("Error reading body: %v", err)
|
|
| 155 |
- w.WriteHeader(http.StatusInternalServerError) |
|
| 156 |
- return |
|
| 157 |
- } |
|
| 158 |
- |
|
| 159 |
- deletions := DeleteManifestsRequest{}
|
|
| 160 |
- err = json.Unmarshal(body, &deletions) |
|
| 161 |
- if err != nil {
|
|
| 162 |
- //TODO |
|
| 163 |
- log.Errorf("Error unmarshaling body: %v", err)
|
|
| 164 |
- w.WriteHeader(http.StatusInternalServerError) |
|
| 165 |
- return |
|
| 166 |
- } |
|
| 167 |
- |
|
| 168 |
- adminService := app.Registry().AdminService() |
|
| 169 |
- errs := []error{}
|
|
| 170 |
- for revision, repos := range deletions {
|
|
| 171 |
- log.Infof("Deleting manifest revision=%q, repos=%v", revision, repos)
|
|
| 172 |
- manifestErrs := adminService.DeleteManifest(revision, repos) |
|
| 173 |
- errs = append(errs, manifestErrs...) |
|
| 174 |
- } |
|
| 175 |
- |
|
| 176 |
- log.Infof("errs=%v", errs)
|
|
| 177 |
- |
|
| 178 |
- //TODO write response |
|
| 179 |
- w.WriteHeader(http.StatusOK) |
|
| 180 |
- } |
|
| 181 |
-} |
|
| 182 |
-*/ |
|
| 183 |
- |
|
| 184 | 25 |
// Execute runs the Docker registry. |
| 185 | 26 |
func Execute(configFile io.Reader) {
|
| 186 | 27 |
config, err := configuration.Parse(configFile) |
| ... | ... |
@@ -199,8 +39,49 @@ func Execute(configFile io.Reader) {
|
| 199 | 199 |
ctx := context.Background() |
| 200 | 200 |
|
| 201 | 201 |
app := handlers.NewApp(ctx, *config) |
| 202 |
- handler := newOpenShiftHandler(app) |
|
| 203 |
- handler = gorillahandlers.CombinedLoggingHandler(os.Stdout, handler) |
|
| 202 |
+ |
|
| 203 |
+ // register OpenShift routes |
|
| 204 |
+ app.RegisterRoute(app.NewRoute().Path("/healthz"), server.HealthzHandler, handlers.NameNotRequired, handlers.NoCustomAccessRecords)
|
|
| 205 |
+ |
|
| 206 |
+ // TODO add https scheme |
|
| 207 |
+ adminRouter := app.NewRoute().PathPrefix("/admin/").Subrouter()
|
|
| 208 |
+ |
|
| 209 |
+ pruneAccessRecords := func(*http.Request) []auth.Access {
|
|
| 210 |
+ return []auth.Access{
|
|
| 211 |
+ {
|
|
| 212 |
+ Resource: auth.Resource{
|
|
| 213 |
+ Type: "admin", |
|
| 214 |
+ }, |
|
| 215 |
+ Action: "prune", |
|
| 216 |
+ }, |
|
| 217 |
+ } |
|
| 218 |
+ } |
|
| 219 |
+ |
|
| 220 |
+ app.RegisterRoute( |
|
| 221 |
+ // DELETE /admin/layers |
|
| 222 |
+ adminRouter.Path("/layers").Methods("DELETE"),
|
|
| 223 |
+ // handler |
|
| 224 |
+ server.DeleteLayersHandler(app.Registry().AdminService()), |
|
| 225 |
+ // repo name not required in url |
|
| 226 |
+ handlers.NameNotRequired, |
|
| 227 |
+ // custom access records |
|
| 228 |
+ pruneAccessRecords, |
|
| 229 |
+ ) |
|
| 230 |
+ |
|
| 231 |
+ app.RegisterRoute( |
|
| 232 |
+ // DELETE /admin/manifests |
|
| 233 |
+ adminRouter.Path("/manifests").Methods("DELETE"),
|
|
| 234 |
+ // handler |
|
| 235 |
+ server.DeleteManifestsHandler(app.Registry().AdminService()), |
|
| 236 |
+ // repo name not required in url |
|
| 237 |
+ handlers.NameNotRequired, |
|
| 238 |
+ // custom access records |
|
| 239 |
+ pruneAccessRecords, |
|
| 240 |
+ ) |
|
| 241 |
+ |
|
| 242 |
+ //app.RegisterRoute(app.NewRoute().Path("/admin/repositories/{repository}/").Methods("DELETE"), server.DeleteRepositoryHandler(app.Registry().AdminService()), func(*http.Request) bool { return true })
|
|
| 243 |
+ |
|
| 244 |
+ handler := gorillahandlers.CombinedLoggingHandler(os.Stdout, app) |
|
| 204 | 245 |
|
| 205 | 246 |
if config.HTTP.TLS.Certificate == "" {
|
| 206 | 247 |
context.GetLogger(app).Infof("listening on %v", config.HTTP.Addr)
|
| ... | ... |
@@ -4,13 +4,14 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io" |
| 6 | 6 |
"net/http" |
| 7 |
+ "time" |
|
| 7 | 8 |
|
| 8 | 9 |
"github.com/golang/glog" |
| 10 |
+ "github.com/openshift/origin/pkg/dockerregistry/server" |
|
| 9 | 11 |
imageapi "github.com/openshift/origin/pkg/image/api" |
| 10 | 12 |
"github.com/openshift/origin/pkg/image/prune" |
| 11 | 13 |
"github.com/spf13/cobra" |
| 12 | 14 |
|
| 13 |
- "github.com/openshift/origin/pkg/cmd/dockerregistry" |
|
| 14 | 15 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 15 | 16 |
) |
| 16 | 17 |
|
| ... | ... |
@@ -18,16 +19,16 @@ const longDesc = ` |
| 18 | 18 |
` |
| 19 | 19 |
|
| 20 | 20 |
type config struct {
|
| 21 |
- DryRun bool |
|
| 22 |
- MinimumResourcePruningAge int |
|
| 23 |
- TagRevisionsToKeep int |
|
| 21 |
+ DryRun bool |
|
| 22 |
+ KeepYoungerThan time.Duration |
|
| 23 |
+ TagRevisionsToKeep int |
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
func NewCmdPruneImages(f *clientcmd.Factory, parentName, name string, out io.Writer) *cobra.Command {
|
| 27 | 27 |
cfg := &config{
|
| 28 |
- DryRun: true, |
|
| 29 |
- MinimumResourcePruningAge: 60, |
|
| 30 |
- TagRevisionsToKeep: 3, |
|
| 28 |
+ DryRun: true, |
|
| 29 |
+ KeepYoungerThan: 60 * time.Minute, |
|
| 30 |
+ TagRevisionsToKeep: 3, |
|
| 31 | 31 |
} |
| 32 | 32 |
|
| 33 | 33 |
cmd := &cobra.Command{
|
| ... | ... |
@@ -45,7 +46,7 @@ func NewCmdPruneImages(f *clientcmd.Factory, parentName, name string, out io.Wri |
| 45 | 45 |
glog.Fatalf("Error getting client: %v", err)
|
| 46 | 46 |
} |
| 47 | 47 |
|
| 48 |
- pruner, err := prune.NewImagePruner(cfg.MinimumResourcePruningAge, cfg.TagRevisionsToKeep, osClient, osClient, kClient, kClient, osClient, osClient, osClient) |
|
| 48 |
+ pruner, err := prune.NewImagePruner(cfg.KeepYoungerThan, cfg.TagRevisionsToKeep, osClient, osClient, kClient, kClient, osClient, osClient, osClient) |
|
| 49 | 49 |
if err != nil {
|
| 50 | 50 |
glog.Fatalf("Error creating image pruner: %v", err)
|
| 51 | 51 |
} |
| ... | ... |
@@ -64,7 +65,7 @@ func NewCmdPruneImages(f *clientcmd.Factory, parentName, name string, out io.Wri |
| 64 | 64 |
prune.DescribingImagePruneFunc(out)(image, referencedStreams) |
| 65 | 65 |
return prune.DeletingImagePruneFunc(osClient.Images(), osClient)(image, referencedStreams) |
| 66 | 66 |
} |
| 67 |
- layerPruneFunc = func(registryURL string, req dockerregistry.DeleteLayersRequest) (error, map[string][]error) {
|
|
| 67 |
+ layerPruneFunc = func(registryURL string, req server.DeleteLayersRequest) (error, map[string][]error) {
|
|
| 68 | 68 |
prune.DescribingLayerPruneFunc(out)(registryURL, req) |
| 69 | 69 |
return prune.DeletingLayerPruneFunc(http.DefaultClient)(registryURL, req) |
| 70 | 70 |
} |
| ... | ... |
@@ -79,7 +80,7 @@ func NewCmdPruneImages(f *clientcmd.Factory, parentName, name string, out io.Wri |
| 79 | 79 |
} |
| 80 | 80 |
|
| 81 | 81 |
cmd.Flags().BoolVar(&cfg.DryRun, "dry-run", cfg.DryRun, "Perform an image pruning dry-run, displaying what would be deleted but not actually deleting anything (default=true).") |
| 82 |
- cmd.Flags().IntVar(&cfg.MinimumResourcePruningAge, "older-than", cfg.MinimumResourcePruningAge, "Specify the minimum age for an image to be prunable, as well as the minimum age for an image stream or pod that references an image to be prunable.") |
|
| 82 |
+ cmd.Flags().DurationVar(&cfg.KeepYoungerThan, "keep-younger-than", cfg.KeepYoungerThan, "Specify the minimum age for an image to be prunable, as well as the minimum age for an image stream or pod that references an image to be prunable.") |
|
| 83 | 83 |
cmd.Flags().IntVar(&cfg.TagRevisionsToKeep, "keep-tag-revisions", cfg.TagRevisionsToKeep, "Specify the number of image revisions for a tag in an image stream that will be preserved.") |
| 84 | 84 |
|
| 85 | 85 |
return cmd |
| 86 | 86 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,188 @@ |
| 0 |
+package server |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "net/http" |
|
| 6 |
+ |
|
| 7 |
+ log "github.com/Sirupsen/logrus" |
|
| 8 |
+ "github.com/docker/distribution" |
|
| 9 |
+ "github.com/docker/distribution/digest" |
|
| 10 |
+ "github.com/docker/distribution/registry/handlers" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+// DeleteLayersRequest is a mapping from layers to the image repositories that |
|
| 14 |
+// reference them. Below is a sample request: |
|
| 15 |
+// |
|
| 16 |
+// {
|
|
| 17 |
+// "layer1": ["repo1", "repo2"], |
|
| 18 |
+// "layer2": ["repo1", "repo3"], |
|
| 19 |
+// ... |
|
| 20 |
+// } |
|
| 21 |
+type DeleteLayersRequest map[string][]string |
|
| 22 |
+ |
|
| 23 |
+// AddLayer adds a layer to the request if it doesn't already exist. |
|
| 24 |
+func (r DeleteLayersRequest) AddLayer(layer string) {
|
|
| 25 |
+ if _, ok := r[layer]; !ok {
|
|
| 26 |
+ r[layer] = []string{}
|
|
| 27 |
+ } |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+// AddStream adds an image stream reference to the layer. |
|
| 31 |
+func (r DeleteLayersRequest) AddStream(layer, stream string) {
|
|
| 32 |
+ r[layer] = append(r[layer], stream) |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+type DeleteLayersResponse struct {
|
|
| 36 |
+ Result string |
|
| 37 |
+ Errors map[string][]string |
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+// deleteLayerFunc returns an http.HandlerFunc that is able to fully delete a |
|
| 41 |
+// layer from storage. |
|
| 42 |
+func DeleteLayersHandler(adminService distribution.AdminService) func(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 43 |
+ return func(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 44 |
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
| 45 |
+ defer req.Body.Close() |
|
| 46 |
+ log.Infof("deleteLayerFunc invoked")
|
|
| 47 |
+ |
|
| 48 |
+ decoder := json.NewDecoder(req.Body) |
|
| 49 |
+ deletions := DeleteLayersRequest{}
|
|
| 50 |
+ if err := decoder.Decode(&deletions); err != nil {
|
|
| 51 |
+ //TODO |
|
| 52 |
+ log.Errorf("Error unmarshaling body: %v", err)
|
|
| 53 |
+ w.WriteHeader(http.StatusInternalServerError) |
|
| 54 |
+ return |
|
| 55 |
+ } |
|
| 56 |
+ |
|
| 57 |
+ errs := map[string][]error{}
|
|
| 58 |
+ for layer, repos := range deletions {
|
|
| 59 |
+ log.Infof("Deleting layer=%q, repos=%v", layer, repos)
|
|
| 60 |
+ errs[layer] = adminService.DeleteLayer(layer, repos) |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ log.Infof("errs=%v", errs)
|
|
| 64 |
+ |
|
| 65 |
+ var result string |
|
| 66 |
+ switch len(errs) {
|
|
| 67 |
+ case 0: |
|
| 68 |
+ result = "success" |
|
| 69 |
+ default: |
|
| 70 |
+ result = "failure" |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ response := DeleteLayersResponse{
|
|
| 74 |
+ Result: result, |
|
| 75 |
+ Errors: map[string][]string{},
|
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ for layer, layerErrors := range errs {
|
|
| 79 |
+ response.Errors[layer] = []string{}
|
|
| 80 |
+ for _, err := range layerErrors {
|
|
| 81 |
+ response.Errors[layer] = append(response.Errors[layer], err.Error()) |
|
| 82 |
+ } |
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
| 86 |
+ encoder := json.NewEncoder(w) |
|
| 87 |
+ if err := encoder.Encode(&response); err != nil {
|
|
| 88 |
+ w.Write([]byte(fmt.Sprintf("Error marshaling response: %v", err)))
|
|
| 89 |
+ w.WriteHeader(http.StatusInternalServerError) |
|
| 90 |
+ return |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ w.WriteHeader(http.StatusOK) |
|
| 94 |
+ }) |
|
| 95 |
+ } |
|
| 96 |
+} |
|
| 97 |
+ |
|
| 98 |
+type DeleteManifestsRequest map[string][]string |
|
| 99 |
+ |
|
| 100 |
+func (r DeleteManifestsRequest) AddManifest(revision string) {
|
|
| 101 |
+ if _, ok := r[revision]; !ok {
|
|
| 102 |
+ r[revision] = []string{}
|
|
| 103 |
+ } |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+func (r DeleteManifestsRequest) AddStream(revision, stream string) {
|
|
| 107 |
+ r[revision] = append(r[revision], stream) |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+type DeleteManifestsResponse struct {
|
|
| 111 |
+ Result string |
|
| 112 |
+ Errors map[string][]string |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+func DeleteManifestsHandler(adminService distribution.AdminService) func(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 116 |
+ return func(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 117 |
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
| 118 |
+ defer req.Body.Close() |
|
| 119 |
+ |
|
| 120 |
+ decoder := json.NewDecoder(req.Body) |
|
| 121 |
+ deletions := DeleteManifestsRequest{}
|
|
| 122 |
+ if err := decoder.Decode(&deletions); err != nil {
|
|
| 123 |
+ //TODO |
|
| 124 |
+ log.Errorf("Error unmarshaling body: %v", err)
|
|
| 125 |
+ w.WriteHeader(http.StatusInternalServerError) |
|
| 126 |
+ return |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ errs := map[string][]error{}
|
|
| 130 |
+ for revision, repos := range deletions {
|
|
| 131 |
+ log.Infof("Deleting manifest revision=%q, repos=%v", revision, repos)
|
|
| 132 |
+ dgst, err := digest.ParseDigest(revision) |
|
| 133 |
+ if err != nil {
|
|
| 134 |
+ errs[revision] = []error{fmt.Errorf("Error parsing revision %q: %v", revision, err)}
|
|
| 135 |
+ continue |
|
| 136 |
+ } |
|
| 137 |
+ errs[revision] = adminService.DeleteManifest(dgst, repos) |
|
| 138 |
+ } |
|
| 139 |
+ |
|
| 140 |
+ log.Infof("errs=%v", errs)
|
|
| 141 |
+ |
|
| 142 |
+ var result string |
|
| 143 |
+ switch len(errs) {
|
|
| 144 |
+ case 0: |
|
| 145 |
+ result = "success" |
|
| 146 |
+ default: |
|
| 147 |
+ result = "failure" |
|
| 148 |
+ } |
|
| 149 |
+ |
|
| 150 |
+ response := DeleteManifestsResponse{
|
|
| 151 |
+ Result: result, |
|
| 152 |
+ Errors: map[string][]string{},
|
|
| 153 |
+ } |
|
| 154 |
+ |
|
| 155 |
+ for revision, revisionErrors := range errs {
|
|
| 156 |
+ response.Errors[revision] = []string{}
|
|
| 157 |
+ for _, err := range revisionErrors {
|
|
| 158 |
+ response.Errors[revision] = append(response.Errors[revision], err.Error()) |
|
| 159 |
+ } |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
| 163 |
+ encoder := json.NewEncoder(w) |
|
| 164 |
+ if err := encoder.Encode(&response); err != nil {
|
|
| 165 |
+ w.Write([]byte(fmt.Sprintf("Error marshaling response: %v", err)))
|
|
| 166 |
+ w.WriteHeader(http.StatusInternalServerError) |
|
| 167 |
+ return |
|
| 168 |
+ } |
|
| 169 |
+ |
|
| 170 |
+ w.WriteHeader(http.StatusOK) |
|
| 171 |
+ }) |
|
| 172 |
+ } |
|
| 173 |
+} |
|
| 174 |
+ |
|
| 175 |
+func DeleteRepositoryHandler(adminService distribution.AdminService) func(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 176 |
+ return func(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 177 |
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
| 178 |
+ defer req.Body.Close() |
|
| 179 |
+ |
|
| 180 |
+ if err := adminService.DeleteRepository(ctx.Repository.Name()); err != nil {
|
|
| 181 |
+ w.Write([]byte(fmt.Sprintf("Error deleting repository %q: %v", ctx.Repository.Name(), err)))
|
|
| 182 |
+ } |
|
| 183 |
+ |
|
| 184 |
+ w.WriteHeader(http.StatusNoContent) |
|
| 185 |
+ }) |
|
| 186 |
+ } |
|
| 187 |
+} |
| ... | ... |
@@ -132,7 +132,7 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg |
| 132 | 132 |
|
| 133 | 133 |
// In case of docker login, hits endpoint /v2 |
| 134 | 134 |
if len(accessRecords) == 0 {
|
| 135 |
- err = VerifyOpenShiftUser(user, client) |
|
| 135 |
+ err = verifyOpenShiftUser(user, client) |
|
| 136 | 136 |
if err != nil {
|
| 137 | 137 |
challenge.err = err |
| 138 | 138 |
return nil, challenge |
| ... | ... |
@@ -143,37 +143,46 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg |
| 143 | 143 |
for _, access := range accessRecords {
|
| 144 | 144 |
log.Debugf("%s:%s:%s", access.Resource.Type, access.Resource.Name, access.Action)
|
| 145 | 145 |
|
| 146 |
- if access.Resource.Type != "repository" {
|
|
| 147 |
- continue |
|
| 148 |
- } |
|
| 149 |
- |
|
| 150 |
- repoParts := strings.SplitN(access.Resource.Name, "/", 2) |
|
| 151 |
- if len(repoParts) != 2 {
|
|
| 152 |
- challenge.err = ErrNamespaceRequired |
|
| 153 |
- return nil, challenge |
|
| 154 |
- } |
|
| 146 |
+ switch access.Resource.Type {
|
|
| 147 |
+ case "repository": |
|
| 148 |
+ repoParts := strings.SplitN(access.Resource.Name, "/", 2) |
|
| 149 |
+ if len(repoParts) != 2 {
|
|
| 150 |
+ challenge.err = ErrNamespaceRequired |
|
| 151 |
+ return nil, challenge |
|
| 152 |
+ } |
|
| 155 | 153 |
|
| 156 |
- verb := "" |
|
| 157 |
- switch access.Action {
|
|
| 158 |
- case "push": |
|
| 159 |
- verb = "update" |
|
| 160 |
- case "pull": |
|
| 161 |
- verb = "get" |
|
| 162 |
- default: |
|
| 163 |
- challenge.err = fmt.Errorf("Unknown action: %s", access.Action)
|
|
| 164 |
- return nil, challenge |
|
| 165 |
- } |
|
| 154 |
+ verb := "" |
|
| 155 |
+ switch access.Action {
|
|
| 156 |
+ case "push": |
|
| 157 |
+ verb = "update" |
|
| 158 |
+ case "pull": |
|
| 159 |
+ verb = "get" |
|
| 160 |
+ default: |
|
| 161 |
+ challenge.err = fmt.Errorf("Unknown action: %s", access.Action)
|
|
| 162 |
+ return nil, challenge |
|
| 163 |
+ } |
|
| 166 | 164 |
|
| 167 |
- err = VerifyOpenShiftAccess(repoParts[0], repoParts[1], verb, client) |
|
| 168 |
- if err != nil {
|
|
| 169 |
- challenge.err = err |
|
| 170 |
- return nil, challenge |
|
| 165 |
+ if err := verifyImageStreamAccess(repoParts[0], repoParts[1], verb, client); err != nil {
|
|
| 166 |
+ challenge.err = err |
|
| 167 |
+ return nil, challenge |
|
| 168 |
+ } |
|
| 169 |
+ case "admin": |
|
| 170 |
+ switch access.Action {
|
|
| 171 |
+ case "prune": |
|
| 172 |
+ if err := verifyPruneAccess(client); err != nil {
|
|
| 173 |
+ challenge.err = err |
|
| 174 |
+ return nil, challenge |
|
| 175 |
+ } |
|
| 176 |
+ default: |
|
| 177 |
+ challenge.err = fmt.Errorf("Unknown action: %s", access.Action)
|
|
| 178 |
+ return nil, challenge |
|
| 179 |
+ } |
|
| 171 | 180 |
} |
| 172 | 181 |
} |
| 173 | 182 |
return WithUserClient(ctx, client), nil |
| 174 | 183 |
} |
| 175 | 184 |
|
| 176 |
-func VerifyOpenShiftUser(user string, client *client.Client) error {
|
|
| 185 |
+func verifyOpenShiftUser(user string, client *client.Client) error {
|
|
| 177 | 186 |
userObj, err := client.Users().Get("~")
|
| 178 | 187 |
if err != nil {
|
| 179 | 188 |
log.Errorf("Get user failed with error: %s", err)
|
| ... | ... |
@@ -186,7 +195,7 @@ func VerifyOpenShiftUser(user string, client *client.Client) error {
|
| 186 | 186 |
return nil |
| 187 | 187 |
} |
| 188 | 188 |
|
| 189 |
-func VerifyOpenShiftAccess(namespace, imageRepo, verb string, client *client.Client) error {
|
|
| 189 |
+func verifyImageStreamAccess(namespace, imageRepo, verb string, client *client.Client) error {
|
|
| 190 | 190 |
sar := authorizationapi.SubjectAccessReview{
|
| 191 | 191 |
Verb: verb, |
| 192 | 192 |
Resource: "imageStreams", |
| ... | ... |
@@ -203,3 +212,20 @@ func VerifyOpenShiftAccess(namespace, imageRepo, verb string, client *client.Cli |
| 203 | 203 |
} |
| 204 | 204 |
return nil |
| 205 | 205 |
} |
| 206 |
+ |
|
| 207 |
+func verifyPruneAccess(client *client.Client) error {
|
|
| 208 |
+ sar := authorizationapi.SubjectAccessReview{
|
|
| 209 |
+ Verb: "delete", |
|
| 210 |
+ Resource: "images", |
|
| 211 |
+ } |
|
| 212 |
+ response, err := client.ClusterSubjectAccessReviews().Create(&sar) |
|
| 213 |
+ if err != nil {
|
|
| 214 |
+ log.Errorf("OpenShift client error: %s", err)
|
|
| 215 |
+ return ErrOpenShiftAccessDenied |
|
| 216 |
+ } |
|
| 217 |
+ if !response.Allowed {
|
|
| 218 |
+ log.Errorf("OpenShift access denied: %s", response.Reason)
|
|
| 219 |
+ return ErrOpenShiftAccessDenied |
|
| 220 |
+ } |
|
| 221 |
+ return nil |
|
| 222 |
+} |
| 206 | 223 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,12 @@ |
| 0 |
+package server |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net/http" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/distribution/health" |
|
| 6 |
+ "github.com/docker/distribution/registry/handlers" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func HealthzHandler(ctx *handlers.Context, r *http.Request) http.Handler {
|
|
| 10 |
+ return http.HandlerFunc(health.StatusHandler) |
|
| 11 |
+} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"io" |
| 9 | 9 |
"io/ioutil" |
| 10 | 10 |
"net/http" |
| 11 |
+ "time" |
|
| 11 | 12 |
|
| 12 | 13 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
| 13 | 14 |
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
| ... | ... |
@@ -20,8 +21,8 @@ import ( |
| 20 | 20 |
buildapi "github.com/openshift/origin/pkg/build/api" |
| 21 | 21 |
buildutil "github.com/openshift/origin/pkg/build/util" |
| 22 | 22 |
"github.com/openshift/origin/pkg/client" |
| 23 |
- "github.com/openshift/origin/pkg/cmd/dockerregistry" |
|
| 24 | 23 |
deployapi "github.com/openshift/origin/pkg/deploy/api" |
| 24 |
+ "github.com/openshift/origin/pkg/dockerregistry/server" |
|
| 25 | 25 |
imageapi "github.com/openshift/origin/pkg/image/api" |
| 26 | 26 |
"github.com/openshift/origin/pkg/image/registry/imagestreamimage" |
| 27 | 27 |
) |
| ... | ... |
@@ -29,8 +30,8 @@ import ( |
| 29 | 29 |
// pruneAlgorithm contains the various settings to use when evaluating images |
| 30 | 30 |
// and layers for pruning. |
| 31 | 31 |
type pruneAlgorithm struct {
|
| 32 |
- minimumAgeInMinutesToPrune int |
|
| 33 |
- tagRevisionsToKeep int |
|
| 32 |
+ keepYoungerThan time.Duration |
|
| 33 |
+ tagRevisionsToKeep int |
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
// ImagePruneFunc is a function that is invoked for each image that is |
| ... | ... |
@@ -40,7 +41,7 @@ type ImagePruneFunc func(image *imageapi.Image, streams []*imageapi.ImageStream) |
| 40 | 40 |
// LayerPruneFunc is a function that is invoked for each registry, along with |
| 41 | 41 |
// a DeleteLayersRequest that contains the layers that can be pruned and the |
| 42 | 42 |
// image stream names that reference each layer. |
| 43 |
-type LayerPruneFunc func(registryURL string, req dockerregistry.DeleteLayersRequest) (requestError error, layerErrors map[string][]error) |
|
| 43 |
+type LayerPruneFunc func(registryURL string, req server.DeleteLayersRequest) (requestError error, layerErrors map[string][]error) |
|
| 44 | 44 |
|
| 45 | 45 |
// ImagePruner knows how to prune images and layers. |
| 46 | 46 |
type ImagePruner interface {
|
| ... | ... |
@@ -59,10 +60,10 @@ var _ ImagePruner = &imagePruner{}
|
| 59 | 59 |
/* |
| 60 | 60 |
NewImagePruner creates a new ImagePruner. |
| 61 | 61 |
|
| 62 |
-minimumAgeInMinutesToPrune is the minimum age, in minutes, that a resource |
|
| 63 |
-must be in order for the image it references (or an image itself) to be a |
|
| 64 |
-candidate for pruning. For example, if minimumAgeInMinutesToPrune is 60, and |
|
| 65 |
-an ImageStream is only 59 minutes old, none of the images it references are |
|
| 62 |
+Images younger than keepYoungerThan and images referenced by image streams |
|
| 63 |
+and/or pods younger than keepYoungerThan are preserved. All other images are |
|
| 64 |
+candidates for pruning. For example, if keepYoungerThan is 60m, and an |
|
| 65 |
+ImageStream is only 59 minutes old, none of the images it references are |
|
| 66 | 66 |
eligible for pruning. |
| 67 | 67 |
|
| 68 | 68 |
tagRevisionsToKeep is the number of revisions per tag in an image stream's |
| ... | ... |
@@ -92,7 +93,7 @@ ImageStreams having a reference to the image in `status.tags`. |
| 92 | 92 |
Also automatically remove any image layer that is no longer referenced by any |
| 93 | 93 |
images. |
| 94 | 94 |
*/ |
| 95 |
-func NewImagePruner(minimumAgeInMinutesToPrune int, tagRevisionsToKeep int, images client.ImagesInterfacer, streams client.ImageStreamsNamespacer, pods kclient.PodsNamespacer, rcs kclient.ReplicationControllersNamespacer, bcs client.BuildConfigsNamespacer, builds client.BuildsNamespacer, dcs client.DeploymentConfigsNamespacer) (ImagePruner, error) {
|
|
| 95 |
+func NewImagePruner(keepYoungerThan time.Duration, tagRevisionsToKeep int, images client.ImagesInterfacer, streams client.ImageStreamsNamespacer, pods kclient.PodsNamespacer, rcs kclient.ReplicationControllersNamespacer, bcs client.BuildConfigsNamespacer, builds client.BuildsNamespacer, dcs client.DeploymentConfigsNamespacer) (ImagePruner, error) {
|
|
| 96 | 96 |
allImages, err := images.Images().List(labels.Everything(), fields.Everything()) |
| 97 | 97 |
if err != nil {
|
| 98 | 98 |
return nil, fmt.Errorf("Error listing images: %v", err)
|
| ... | ... |
@@ -128,18 +129,18 @@ func NewImagePruner(minimumAgeInMinutesToPrune int, tagRevisionsToKeep int, imag |
| 128 | 128 |
return nil, fmt.Errorf("Error listing deployment configs: %v", err)
|
| 129 | 129 |
} |
| 130 | 130 |
|
| 131 |
- return newImagePruner(minimumAgeInMinutesToPrune, tagRevisionsToKeep, allImages, allStreams, allPods, allRCs, allBCs, allBuilds, allDCs), nil |
|
| 131 |
+ return newImagePruner(keepYoungerThan, tagRevisionsToKeep, allImages, allStreams, allPods, allRCs, allBCs, allBuilds, allDCs), nil |
|
| 132 | 132 |
} |
| 133 | 133 |
|
| 134 | 134 |
// newImagePruner creates a new ImagePruner. |
| 135 |
-func newImagePruner(minimumAgeInMinutesToPrune int, tagRevisionsToKeep int, images *imageapi.ImageList, streams *imageapi.ImageStreamList, pods *kapi.PodList, rcs *kapi.ReplicationControllerList, bcs *buildapi.BuildConfigList, builds *buildapi.BuildList, dcs *deployapi.DeploymentConfigList) ImagePruner {
|
|
| 135 |
+func newImagePruner(keepYoungerThan time.Duration, tagRevisionsToKeep int, images *imageapi.ImageList, streams *imageapi.ImageStreamList, pods *kapi.PodList, rcs *kapi.ReplicationControllerList, bcs *buildapi.BuildConfigList, builds *buildapi.BuildList, dcs *deployapi.DeploymentConfigList) ImagePruner {
|
|
| 136 | 136 |
g := graph.New() |
| 137 | 137 |
|
| 138 |
- glog.V(1).Infof("Creating image pruner with minimumAgeInMinutesToPrune=%d, tagRevisionsToKeep=%d", minimumAgeInMinutesToPrune, tagRevisionsToKeep)
|
|
| 138 |
+ glog.V(1).Infof("Creating image pruner with keepYoungerThan=%v, tagRevisionsToKeep=%d", keepYoungerThan, tagRevisionsToKeep)
|
|
| 139 | 139 |
|
| 140 | 140 |
algorithm := pruneAlgorithm{
|
| 141 |
- minimumAgeInMinutesToPrune: minimumAgeInMinutesToPrune, |
|
| 142 |
- tagRevisionsToKeep: tagRevisionsToKeep, |
|
| 141 |
+ keepYoungerThan: keepYoungerThan, |
|
| 142 |
+ tagRevisionsToKeep: tagRevisionsToKeep, |
|
| 143 | 143 |
} |
| 144 | 144 |
|
| 145 | 145 |
addImagesToGraph(g, images, algorithm) |
| ... | ... |
@@ -176,9 +177,8 @@ func addImagesToGraph(g graph.Graph, images *imageapi.ImageList, algorithm prune |
| 176 | 176 |
} |
| 177 | 177 |
|
| 178 | 178 |
age := util.Now().Sub(image.CreationTimestamp.Time) |
| 179 |
- ageInMinutes := int(age.Minutes()) |
|
| 180 |
- if ageInMinutes < algorithm.minimumAgeInMinutesToPrune {
|
|
| 181 |
- glog.V(4).Infof("Image %q is younger than minimum pruning age, skipping (age=%d)", image.Name, ageInMinutes)
|
|
| 179 |
+ if age < algorithm.keepYoungerThan {
|
|
| 180 |
+ glog.V(4).Infof("Image %q is younger than minimum pruning age, skipping (age=%v)", image.Name, age)
|
|
| 182 | 181 |
continue |
| 183 | 182 |
} |
| 184 | 183 |
|
| ... | ... |
@@ -218,7 +218,7 @@ func addImageStreamsToGraph(g graph.Graph, streams *imageapi.ImageStreamList, al |
| 218 | 218 |
oldImageRevisionReferenceKind := graph.WeakReferencedImageGraphEdgeKind |
| 219 | 219 |
|
| 220 | 220 |
age := util.Now().Sub(stream.CreationTimestamp.Time) |
| 221 |
- if int(age.Minutes()) < algorithm.minimumAgeInMinutesToPrune {
|
|
| 221 |
+ if age < algorithm.keepYoungerThan {
|
|
| 222 | 222 |
// stream's age is below threshold - use a strong reference for old image revisions instead |
| 223 | 223 |
glog.V(4).Infof("Stream %s/%s is below age threshold - none of its images are eligible for pruning", stream.Namespace, stream.Name)
|
| 224 | 224 |
oldImageRevisionReferenceKind = graph.ReferencedImageGraphEdgeKind |
| ... | ... |
@@ -277,7 +277,7 @@ func addPodsToGraph(g graph.Graph, pods *kapi.PodList, algorithm pruneAlgorithm) |
| 277 | 277 |
|
| 278 | 278 |
if pod.Status.Phase != kapi.PodRunning && pod.Status.Phase != kapi.PodPending {
|
| 279 | 279 |
age := util.Now().Sub(pod.CreationTimestamp.Time) |
| 280 |
- if int(age.Minutes()) >= algorithm.minimumAgeInMinutesToPrune {
|
|
| 280 |
+ if age >= algorithm.keepYoungerThan {
|
|
| 281 | 281 |
glog.V(4).Infof("Pod %s/%s is not running or pending and age is at least minimum pruning age - skipping", pod.Namespace, pod.Name)
|
| 282 | 282 |
// not pending or running, age is at least minimum pruning age, skip |
| 283 | 283 |
continue |
| ... | ... |
@@ -538,10 +538,10 @@ func streamLayerReferences(g graph.Graph, layerNode *graph.ImageLayerNode) []*gr |
| 538 | 538 |
} |
| 539 | 539 |
|
| 540 | 540 |
// pruneLayers creates a mapping of registryURLs to |
| 541 |
-// dockerregistry.DeleteLayersRequest objects, invoking layerPruneFunc for each |
|
| 541 |
+// server.DeleteLayersRequest objects, invoking layerPruneFunc for each |
|
| 542 | 542 |
// registryURL and request. |
| 543 | 543 |
func pruneLayers(g graph.Graph, layerNodes []*graph.ImageLayerNode, layerPruneFunc LayerPruneFunc) {
|
| 544 |
- registryDeletionRequests := map[string]dockerregistry.DeleteLayersRequest{}
|
|
| 544 |
+ registryDeletionRequests := map[string]server.DeleteLayersRequest{}
|
|
| 545 | 545 |
|
| 546 | 546 |
for _, layerNode := range layerNodes {
|
| 547 | 547 |
glog.V(4).Infof("Examining layer %q", layerNode.Layer)
|
| ... | ... |
@@ -571,7 +571,7 @@ func pruneLayers(g graph.Graph, layerNodes []*graph.ImageLayerNode, layerPruneFu |
| 571 | 571 |
deletionRequest, ok := registryDeletionRequests[ref.Registry] |
| 572 | 572 |
if !ok {
|
| 573 | 573 |
glog.V(4).Infof("Request not found - creating new one")
|
| 574 |
- deletionRequest = dockerregistry.DeleteLayersRequest{}
|
|
| 574 |
+ deletionRequest = server.DeleteLayersRequest{}
|
|
| 575 | 575 |
registryDeletionRequests[ref.Registry] = deletionRequest |
| 576 | 576 |
} |
| 577 | 577 |
|
| ... | ... |
@@ -648,7 +648,7 @@ func DeletingImagePruneFunc(images client.ImageInterface, streams client.ImageSt |
| 648 | 648 |
// DescribingLayerPruneFunc returns a LayerPruneFunc that writes information |
| 649 | 649 |
// about the layers that are eligible for pruning to out. |
| 650 | 650 |
func DescribingLayerPruneFunc(out io.Writer) LayerPruneFunc {
|
| 651 |
- return func(registryURL string, deletions dockerregistry.DeleteLayersRequest) (error, map[string][]error) {
|
|
| 651 |
+ return func(registryURL string, deletions server.DeleteLayersRequest) (error, map[string][]error) {
|
|
| 652 | 652 |
result := map[string][]error{}
|
| 653 | 653 |
|
| 654 | 654 |
fmt.Fprintf(out, "Pruning from registry %q\n", registryURL) |
| ... | ... |
@@ -676,7 +676,7 @@ func DescribingLayerPruneFunc(out io.Writer) LayerPruneFunc {
|
| 676 | 676 |
// key being a layer, and each value being a list of Docker image repository |
| 677 | 677 |
// names referenced by the layer. |
| 678 | 678 |
func DeletingLayerPruneFunc(registryClient *http.Client) LayerPruneFunc {
|
| 679 |
- return func(registryURL string, deletions dockerregistry.DeleteLayersRequest) (requestError error, layerErrors map[string][]error) {
|
|
| 679 |
+ return func(registryURL string, deletions server.DeleteLayersRequest) (requestError error, layerErrors map[string][]error) {
|
|
| 680 | 680 |
glog.V(4).Infof("Starting pruning of layers from %q, req %#v", registryURL, deletions)
|
| 681 | 681 |
body, err := json.Marshal(&deletions) |
| 682 | 682 |
if err != nil {
|
| ... | ... |
@@ -710,7 +710,7 @@ func DeletingLayerPruneFunc(registryClient *http.Client) LayerPruneFunc {
|
| 710 | 710 |
return fmt.Errorf("Unexpected status code %d in response %s", resp.StatusCode, buf), nil
|
| 711 | 711 |
} |
| 712 | 712 |
|
| 713 |
- var deleteResponse dockerregistry.DeleteLayersResponse |
|
| 713 |
+ var deleteResponse server.DeleteLayersResponse |
|
| 714 | 714 |
if err := json.Unmarshal(buf, &deleteResponse); err != nil {
|
| 715 | 715 |
glog.Errorf("Error unmarshaling response: %v", err)
|
| 716 | 716 |
return fmt.Errorf("Error unmarshaling response: %v", err), nil
|
| ... | ... |
@@ -4,7 +4,7 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io" |
| 6 | 6 |
|
| 7 |
- "github.com/openshift/origin/pkg/cmd/dockerregistry" |
|
| 7 |
+ "github.com/openshift/origin/pkg/dockerregistry/server" |
|
| 8 | 8 |
imageapi "github.com/openshift/origin/pkg/image/api" |
| 9 | 9 |
) |
| 10 | 10 |
|
| ... | ... |
@@ -93,7 +93,7 @@ func (p *summarizingPruner) imagePruneFunc(base ImagePruneFunc) ImagePruneFunc {
|
| 93 | 93 |
} |
| 94 | 94 |
|
| 95 | 95 |
func (p *summarizingPruner) layerPruneFunc(base LayerPruneFunc) LayerPruneFunc {
|
| 96 |
- return func(registryURL string, req dockerregistry.DeleteLayersRequest) (error, map[string][]error) {
|
|
| 96 |
+ return func(registryURL string, req server.DeleteLayersRequest) (error, map[string][]error) {
|
|
| 97 | 97 |
requestError, layerErrors := base(registryURL, req) |
| 98 | 98 |
p.registryResults[registryURL] = registryResult{
|
| 99 | 99 |
requestError: requestError, |