From 14484491bd52114232b9652ff1361008917c368b Mon Sep 17 00:00:00 2001 From: Muhammad Talal Anwar Date: Thu, 24 Sep 2020 06:34:15 +0200 Subject: [PATCH] nfs-shares: add upper limit support for MaxSize --- internal/api/api.go | 5 +++-- internal/api/resources.go | 18 ++++++++++++++++-- internal/api/shared_test.go | 2 +- internal/core/config.go | 28 ++++++++++++++++++++++++++++ main.go | 36 +++++++++++++++++++++++++++++++++--- 5 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 internal/core/config.go diff --git a/internal/api/api.go b/internal/api/api.go index b19bea04..8efd9174 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -39,6 +39,7 @@ import ( ) type handler struct { + Config *core.Config DB *gorp.DbMap Team core.AssetManagerTeam Validator gopherpolicy.Validator @@ -49,8 +50,8 @@ type handler struct { } //NewHandler constructs the main http.Handler for this package. -func NewHandler(dbi *gorp.DbMap, team core.AssetManagerTeam, validator gopherpolicy.Validator, provider core.ProviderClientInterface) http.Handler { - h := &handler{DB: dbi, Team: team, Validator: validator, Provider: provider, TimeNow: time.Now} +func NewHandler(cfg *core.Config, dbi *gorp.DbMap, team core.AssetManagerTeam, validator gopherpolicy.Validator, provider core.ProviderClientInterface) http.Handler { + h := &handler{Config: cfg, DB: dbi, Team: team, Validator: validator, Provider: provider, TimeNow: time.Now} return h.BuildRouter() } diff --git a/internal/api/resources.go b/internal/api/resources.go index dcf86681..d0c9d0da 100644 --- a/internal/api/resources.go +++ b/internal/api/resources.go @@ -19,6 +19,7 @@ package api import ( + "fmt" "net/http" "strings" "time" @@ -115,7 +116,7 @@ func (h handler) ResourceFromDB(res db.Resource) (Resource, error) { //UpdateDBResource updates the given db.Resource with the values provided in //this api.Resource. -func (r Resource) UpdateDBResource(res *db.Resource, info core.AssetTypeInfo) (errors []string) { +func (r Resource) UpdateDBResource(res *db.Resource, info core.AssetTypeInfo, maxAssetSize *uint64) (errors []string) { complain := func(msg string) { errors = append(errors, msg) } if r.ScrapedAtUnix != nil { @@ -203,11 +204,23 @@ func (r Resource) UpdateDBResource(res *db.Resource, info core.AssetTypeInfo) (e } } + isNFS := string(info.AssetType) == "nfs-shares" if r.SizeConstraints == nil { + if isNFS { + complain("maximum size must be configured for nfs-shares") + } res.MinimumSize = nil res.MaximumSize = nil res.MinimumFreeSize = nil } else { + if isNFS { + if res.MaximumSize == nil { + complain("maximum size must be configured for nfs-shares") + } else if maxAssetSize != nil && *res.MaximumSize > *maxAssetSize { + complain(fmt.Sprintf("maximum size must be less than %d", *maxAssetSize)) + } + } + res.MinimumSize = r.SizeConstraints.Minimum if res.MinimumSize != nil && *res.MinimumSize == 0 { res.MinimumSize = nil @@ -309,6 +322,7 @@ func (h handler) PutResource(w http.ResponseWriter, r *http.Request) { } manager, info := h.Team.ForAssetType(dbResource.AssetType) + maxAssetSize := h.Config.MaxAssetSize[info.AssetType] err := manager.CheckResourceAllowed(dbResource.AssetType, dbResource.ScopeUUID) if err != nil { http.Error(w, err.Error(), http.StatusUnprocessableEntity) @@ -335,7 +349,7 @@ func (h handler) PutResource(w http.ResponseWriter, r *http.Request) { }) } - errs := input.UpdateDBResource(dbResource, info) + errs := input.UpdateDBResource(dbResource, info, maxAssetSize) if len(errs) > 0 { doAudit(http.StatusUnprocessableEntity) http.Error(w, strings.Join(errs, "\n"), http.StatusUnprocessableEntity) diff --git a/internal/api/shared_test.go b/internal/api/shared_test.go index 7cdd2a6a..b2ded1fd 100644 --- a/internal/api/shared_test.go +++ b/internal/api/shared_test.go @@ -53,7 +53,7 @@ func withHandler(t test.T, timeNow func() time.Time, action func(*handler, http. if timeNow == nil { timeNow = time.Now } - h := &handler{DB: dbi, Team: team, Validator: mv, Provider: MockProviderClient{}, TimeNow: timeNow} + h := &handler{Config: &core.Config{}, DB: dbi, Team: team, Validator: mv, Provider: MockProviderClient{}, TimeNow: timeNow} action(h, h.BuildRouter(), mv, resources, assets) }) } diff --git a/internal/core/config.go b/internal/core/config.go new file mode 100644 index 00000000..6d28e39b --- /dev/null +++ b/internal/core/config.go @@ -0,0 +1,28 @@ +/****************************************************************************** +* +* Copyright 2020 SAP SE +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************************/ + +package core + +import ( + "github.com/sapcc/castellum/internal/db" +) + +//Config contains the app-level configuration options. +type Config struct { + MaxAssetSize map[db.AssetType]*uint64 +} diff --git a/main.go b/main.go index 0a578292..117b446b 100644 --- a/main.go +++ b/main.go @@ -104,6 +104,36 @@ func main() { logg.Fatal(err.Error()) } + //get max asset sizes + cfg := core.Config{ + MaxAssetSize: make(map[db.AssetType]*uint64), + } + maxAssetSizes := strings.Split(mustGetenv("CASTELLUM_MAX_ASSET_SIZES"), ",") + for _, v := range maxAssetSizes { + sL := strings.Split(v, "=") + if len(sL) != 2 { + logg.Fatal("expected a max asset size configuration value in the format: ':', got: %s", v) + } + assetType := sL[0] + maxSize, err := strconv.ParseUint(sL[1], 10, 64) + if err != nil { + logg.Fatal(err.Error()) + } + + found := false + for _, assetManager := range team { + for _, info := range assetManager.AssetTypes() { + if assetType == string(info.AssetType) { + found = true + cfg.MaxAssetSize[info.AssetType] = &maxSize + } + } + } + if !found { + logg.Fatal("unknown asset type: %s", assetType) + } + } + if len(os.Args) < 2 { usage() } @@ -112,7 +142,7 @@ func main() { if len(os.Args) != 2 { usage() } - runAPI(dbi, team, providerClient, eo, httpListenAddr) + runAPI(&cfg, dbi, team, providerClient, eo, httpListenAddr) case "observer": if len(os.Args) != 2 { usage() @@ -144,7 +174,7 @@ func mustGetenv(key string) string { //////////////////////////////////////////////////////////////////////////////// // task: API -func runAPI(dbi *gorp.DbMap, team core.AssetManagerTeam, providerClient *core.ProviderClient, eo gophercloud.EndpointOpts, httpListenAddr string) { +func runAPI(cfg *core.Config, dbi *gorp.DbMap, team core.AssetManagerTeam, providerClient *core.ProviderClient, eo gophercloud.EndpointOpts, httpListenAddr string) { tv := gopherpolicy.TokenValidator{ IdentityV3: providerClient.KeystoneV3, Cacher: gopherpolicy.InMemoryCacher(), @@ -157,7 +187,7 @@ func runAPI(dbi *gorp.DbMap, team core.AssetManagerTeam, providerClient *core.Pr //wrap the main API handler in several layers of middleware (CORS is //deliberately the outermost middleware, to exclude preflight checks from //logging) - handler := api.NewHandler(dbi, team, &tv, providerClient) + handler := api.NewHandler(cfg, dbi, team, &tv, providerClient) handler = logg.Middleware{}.Wrap(handler) handler = cors.New(cors.Options{ AllowedOrigins: []string{"*"},