Browse code

Allow to toggle quota enforcement in the registry

- Registry recognizes
REGISTRY_MIDDLEWARE_REPOSITORY_OPENSHIFT_ENFORCEQUOTA environment
variable. If set to "true", registry will refuse to write any blob
until it can fetch quota and limit range objects from origin server.
It defaults to "false".
- Added "--enforce-quota" flag to `oadm registry` command that sets the
env var. By default it's `true` so that new deployment configs can
enforce the quota in the registry.

Signed-off-by: Michal Minar <miminar@redhat.com>

Michal Minar authored on 2016/05/09 18:40:29
Showing 7 changed files
... ...
@@ -1493,6 +1493,7 @@ _oadm_registry()
1493 1493
     flags_completion+=("__handle_filename_extension_flag kubeconfig")
1494 1494
     flags+=("--daemonset")
1495 1495
     flags+=("--dry-run")
1496
+    flags+=("--enforce-quota")
1496 1497
     flags+=("--images=")
1497 1498
     flags+=("--labels=")
1498 1499
     flags+=("--latest-images")
... ...
@@ -4513,6 +4513,7 @@ _oc_adm_registry()
4513 4513
     flags_completion+=("__handle_filename_extension_flag kubeconfig")
4514 4514
     flags+=("--daemonset")
4515 4515
     flags+=("--dry-run")
4516
+    flags+=("--enforce-quota")
4516 4517
     flags+=("--images=")
4517 4518
     flags+=("--labels=")
4518 4519
     flags+=("--latest-images")
... ...
@@ -2069,6 +2069,7 @@ _openshift_admin_registry()
2069 2069
     flags_completion+=("__handle_filename_extension_flag kubeconfig")
2070 2070
     flags+=("--daemonset")
2071 2071
     flags+=("--dry-run")
2072
+    flags+=("--enforce-quota")
2072 2073
     flags+=("--images=")
2073 2074
     flags+=("--labels=")
2074 2075
     flags+=("--latest-images")
... ...
@@ -8100,6 +8101,7 @@ _openshift_cli_adm_registry()
8100 8100
     flags_completion+=("__handle_filename_extension_flag kubeconfig")
8101 8101
     flags+=("--daemonset")
8102 8102
     flags+=("--dry-run")
8103
+    flags+=("--enforce-quota")
8103 8104
     flags+=("--images=")
8104 8105
     flags+=("--labels=")
8105 8106
     flags+=("--latest-images")
... ...
@@ -18,3 +18,4 @@ middleware:
18 18
     - name: openshift
19 19
       options:
20 20
         pullthrough: true
21
+        enforcequota: false
... ...
@@ -83,6 +83,7 @@ type RegistryConfig struct {
83 83
 	Selector       string
84 84
 	ServiceAccount string
85 85
 	DaemonSet      bool
86
+	EnforceQuota   bool
86 87
 
87 88
 	ServingCertPath string
88 89
 	ServingKeyPath  string
... ...
@@ -121,6 +122,7 @@ func NewCmdRegistry(f *clientcmd.Factory, parentName, name string, out io.Writer
121 121
 		Volume:         "/registry",
122 122
 		ServiceAccount: "registry",
123 123
 		Replicas:       1,
124
+		EnforceQuota:   true,
124 125
 	}
125 126
 
126 127
 	cmd := &cobra.Command{
... ...
@@ -153,6 +155,7 @@ func NewCmdRegistry(f *clientcmd.Factory, parentName, name string, out io.Writer
153 153
 	cmd.Flags().StringVar(&cfg.ServingCertPath, "tls-certificate", cfg.ServingCertPath, "An optional path to a PEM encoded certificate (which may contain the private key) for serving over TLS")
154 154
 	cmd.Flags().StringVar(&cfg.ServingKeyPath, "tls-key", cfg.ServingKeyPath, "An optional path to a PEM encoded private key for serving over TLS")
155 155
 	cmd.Flags().BoolVar(&cfg.DaemonSet, "daemonset", cfg.DaemonSet, "Use a daemonset instead of a deployment config.")
156
+	cmd.Flags().BoolVar(&cfg.EnforceQuota, "enforce-quota", cfg.EnforceQuota, "If set, the registry will refuse to write blobs if they exceed quota limits")
156 157
 
157 158
 	// autocompletion hints
158 159
 	cmd.MarkFlagFilename("credentials", "kubeconfig")
... ...
@@ -303,6 +306,11 @@ func RunCmdRegistry(f *clientcmd.Factory, cmd *cobra.Command, out io.Writer, cfg
303 303
 	env := app.Environment{}
304 304
 	env.Add(secretEnv)
305 305
 
306
+	enforceQuota := "false"
307
+	if cfg.EnforceQuota {
308
+		enforceQuota = "true"
309
+	}
310
+	env["REGISTRY_MIDDLEWARE_REPOSITORY_OPENSHIFT_ENFORCEQUOTA"] = enforceQuota
306 311
 	healthzPort := defaultPort
307 312
 	if len(ports) > 0 {
308 313
 		healthzPort = ports[0].ContainerPort
... ...
@@ -13,6 +13,8 @@
13 13
 package server
14 14
 
15 15
 import (
16
+	"fmt"
17
+
16 18
 	"github.com/docker/distribution"
17 19
 	"github.com/docker/distribution/context"
18 20
 
... ...
@@ -21,6 +23,44 @@ import (
21 21
 	imageadmission "github.com/openshift/origin/pkg/image/admission"
22 22
 )
23 23
 
24
+// newQuotaEnforcingConfig creates a configuration for quotaRestrictedBlobStore.
25
+func newQuotaEnforcingConfig(ctx context.Context, enforceQuota string, options map[string]interface{}) *quotaEnforcingConfig {
26
+	buildOptionValues := func(optionName string, override string) []string {
27
+		optValues := []string{}
28
+		if value, ok := options[optionName]; ok {
29
+			var res string
30
+			switch v := value.(type) {
31
+			case string:
32
+				res = v
33
+			case bool:
34
+				res = fmt.Sprintf("%t", v)
35
+			default:
36
+				res = fmt.Sprintf("%v", v)
37
+			}
38
+			optValues = append(optValues, res)
39
+		}
40
+		optValues = append(optValues, override)
41
+		return optValues
42
+	}
43
+
44
+	enforce := false
45
+	for _, s := range buildOptionValues("enforcequota", enforceQuota) {
46
+		enforce = s == "true"
47
+	}
48
+	if !enforce {
49
+		context.GetLogger(ctx).Info("quota enforcement disabled")
50
+	}
51
+	return &quotaEnforcingConfig{
52
+		enforcementDisabled: !enforce,
53
+	}
54
+}
55
+
56
+// quotaEnforcingConfig holds configuration for quotaRestrictedBlobStore.
57
+type quotaEnforcingConfig struct {
58
+	// if set, disables quota enforcement
59
+	enforcementDisabled bool
60
+}
61
+
24 62
 // quotaRestrictedBlobStore wraps upstream blob store with a guard preventing big layers exceeding image quotas
25 63
 // from being saved.
26 64
 type quotaRestrictedBlobStore struct {
... ...
@@ -30,6 +30,11 @@ const (
30 30
 	// DockerRegistryURLEnvVar is a mandatory environment variable name specifying url of internal docker
31 31
 	// registry. All references to pushed images will be prefixed with its value.
32 32
 	DockerRegistryURLEnvVar = "DOCKER_REGISTRY_URL"
33
+
34
+	// EnforceQuotaEnvVar is a boolean environment variable that allows to turn quota enforcement on or off.
35
+	// By default, quota enforcement is off. It overrides openshift middleware configuration option.
36
+	// Recognized values are "true" and "false".
37
+	EnforceQuotaEnvVar = "REGISTRY_MIDDLEWARE_REPOSITORY_OPENSHIFT_ENFORCEQUOTA"
33 38
 )
34 39
 
35 40
 var (
... ...
@@ -42,6 +47,9 @@ var (
42 42
 	// insecureTransport is the transport pool that does not verify remote TLS certificates for use
43 43
 	// during pullthrough against registries marked as insecure.
44 44
 	insecureTransport http.RoundTripper
45
+	// quotaEnforcing contains shared caches of quota objects keyed by project name. Will be initialized
46
+	// only if the quota is enforced. See EnforceQuotaEnvVar.
47
+	quotaEnforcing *quotaEnforcingConfig
45 48
 )
46 49
 
47 50
 func init() {
... ...
@@ -59,6 +67,9 @@ func init() {
59 59
 			if err != nil {
60 60
 				return nil, err
61 61
 			}
62
+			if quotaEnforcing == nil {
63
+				quotaEnforcing = newQuotaEnforcingConfig(ctx, os.Getenv(EnforceQuotaEnvVar), options)
64
+			}
62 65
 			return newRepositoryWithClient(registryOSClient, kClient, kClient, ctx, repo, options)
63 66
 		},
64 67
 	)
... ...
@@ -152,10 +163,12 @@ func (r *repository) Blobs(ctx context.Context) distribution.BlobStore {
152 152
 
153 153
 	bs := r.Repository.Blobs(ctx)
154 154
 
155
-	bs = &quotaRestrictedBlobStore{
156
-		BlobStore: bs,
155
+	if quotaEnforcing != nil {
156
+		bs = &quotaRestrictedBlobStore{
157
+			BlobStore: bs,
157 158
 
158
-		repo: &repo,
159
+			repo: &repo,
160
+		}
159 161
 	}
160 162
 
161 163
 	if r.pullthrough {