- 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>
... | ... |
@@ -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") |
... | ... |
@@ -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 "aEnforcingConfig{ |
|
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 = "aRestrictedBlobStore{ |
|
156 |
- BlobStore: bs, |
|
155 |
+ if quotaEnforcing != nil { |
|
156 |
+ bs = "aRestrictedBlobStore{ |
|
157 |
+ BlobStore: bs, |
|
157 | 158 |
|
158 |
- repo: &repo, |
|
159 |
+ repo: &repo, |
|
160 |
+ } |
|
159 | 161 |
} |
160 | 162 |
|
161 | 163 |
if r.pullthrough { |