Skip to content

Commit 0bc0783

Browse files
authored
Merge pull request #2219 from weaveworks/csv-pricing
Csv pricing
2 parents 0a6fdf6 + 27c3bfc commit 0bc0783

File tree

10 files changed

+448
-116
lines changed

10 files changed

+448
-116
lines changed

charts/mccp/templates/clusters-service/deployment.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ spec:
9797
{{- if .Values.config.extraVolumeMounts }}
9898
{{- include "common.tplvalues.render" (dict "value" .Values.config.extraVolumeMounts "context" $) | nindent 12 }}
9999
{{- end }}
100+
{{- if .Values.extraVolumeMounts }}
101+
{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }}
102+
{{- end }}
100103
volumes:
101104
{{- if .Values.tls.secretName }}
102105
- name: clusters-service-tls-volume
@@ -108,3 +111,6 @@ spec:
108111
{{- if .Values.config.extraVolumes }}
109112
{{- include "common.tplvalues.render" (dict "value" .Values.config.extraVolumes "context" $) | nindent 6 }}
110113
{{- end }}
114+
{{- if .Values.extraVolumes }}
115+
{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 6 }}
116+
{{- end }}

cmd/clusters-service/app/server.go

Lines changed: 104 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"time"
2424

2525
"github.com/NYTimes/gziphandler"
26-
2726
awsconfig "github.com/aws/aws-sdk-go-v2/config"
2827
"github.com/aws/aws-sdk-go-v2/service/pricing"
2928
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -32,6 +31,7 @@ import (
3231
"github.com/go-logr/logr"
3332
grpc_runtime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
3433
"github.com/spf13/cobra"
34+
flag "github.com/spf13/pflag"
3535
"github.com/spf13/viper"
3636
gitopsv1alpha1 "github.com/weaveworks/cluster-controller/api/v1alpha1"
3737
"github.com/weaveworks/go-checkpoint"
@@ -77,7 +77,6 @@ import (
7777
corev1 "k8s.io/api/core/v1"
7878
"k8s.io/apimachinery/pkg/runtime"
7979
"k8s.io/apimachinery/pkg/types"
80-
runtimeUtil "k8s.io/apimachinery/pkg/util/runtime"
8180
"k8s.io/client-go/discovery"
8281
"k8s.io/client-go/informers"
8382
"k8s.io/client-go/kubernetes"
@@ -139,10 +138,11 @@ type Params struct {
139138
DevMode bool `mapstructure:"dev-mode"`
140139
Cluster string `mapstructure:"cluster-name"`
141140
UseK8sCachedClients bool `mapstructure:"use-k8s-cached-clients"`
142-
CostEstimationFilters string `mapstructure:"cost-estimation-filters"`
143-
CostEstimationAPIRegion string `mapstructure:"cost-estimation-api-region"`
144141
UIConfig string `mapstructure:"ui-config"`
145142
PipelineControllerAddress string `mapstructure:"pipeline-controller-address"`
143+
CostEstimationFilters string `mapstructure:"cost-estimation-filters"`
144+
CostEstimationAPIRegion string `mapstructure:"cost-estimation-api-region"`
145+
CostEstimationFilename string `mapstructure:"cost-estimation-csv-file"`
146146
}
147147

148148
type OIDCAuthenticationOptions struct {
@@ -183,60 +183,60 @@ func NewAPIServerCommand(log logr.Logger, tempDir string) *cobra.Command {
183183
},
184184
}
185185

186+
cmdFlags := cmd.Flags()
187+
186188
// Have to declare a flag for viper to correctly read and then bind environment variables too
187189
// FIXME: why? We don't actually use the flags in helm templates etc.
188190
//
189-
cmd.Flags().String("entitlement-secret-name", ent.DefaultSecretName, "The name of the entitlement secret")
190-
cmd.Flags().String("entitlement-secret-namespace", "flux-system", "The namespace of the entitlement secret")
191-
cmd.Flags().String("helm-repo-namespace", os.Getenv("RUNTIME_NAMESPACE"), "the namespace of the Helm Repository resource to scan for profiles")
192-
cmd.Flags().String("helm-repo-name", "weaveworks-charts", "the name of the Helm Repository resource to scan for profiles")
193-
cmd.Flags().String("profile-cache-location", "/tmp/helm-cache", "the location where the cache Profile data lives")
194-
cmd.Flags().String("html-root-path", "/html", "Where to serve static assets from")
195-
cmd.Flags().String("git-provider-type", "", "")
196-
cmd.Flags().String("git-provider-hostname", "", "")
197-
cmd.Flags().Bool("capi-enabled", true, "")
198-
cmd.Flags().String("capi-clusters-namespace", corev1.NamespaceAll, "where to look for GitOps cluster resources, defaults to looking in all namespaces")
199-
cmd.Flags().String("capi-templates-namespace", "", "where to look for CAPI template resources, required")
200-
cmd.Flags().String("inject-prune-annotation", "", "")
201-
cmd.Flags().String("add-bases-kustomization", "enabled", "Add a kustomization to point to ./bases when creating leaf clusters")
202-
cmd.Flags().String("capi-templates-repository-url", "", "")
203-
cmd.Flags().String("capi-repository-path", "", "")
204-
cmd.Flags().String("capi-repository-clusters-path", "./clusters", "")
205-
cmd.Flags().String("capi-templates-repository-api-url", "", "")
206-
cmd.Flags().String("capi-templates-repository-base-branch", "", "")
207-
cmd.Flags().String("runtime-namespace", "flux-system", "Namespace hosting Gitops configuration objects (e.g. cluster-user-auth secrets)")
208-
cmd.Flags().String("git-provider-token", "", "")
209-
cmd.Flags().String("tls-cert-file", "", "filename for the TLS certficate, in-memory generated if omitted")
210-
cmd.Flags().String("tls-private-key", "", "filename for the TLS key, in-memory generated if omitted")
211-
cmd.Flags().Bool("no-tls", false, "do not attempt to read TLS certificates")
212-
cmd.Flags().String("cluster-name", "management", "name of the management cluster")
213-
214-
cmd.Flags().StringSlice("auth-methods", []string{"oidc", "token-passthrough", "user-account"}, "Which auth methods to use, valid values are 'oidc', 'token-pass-through' and 'user-account'")
215-
cmd.Flags().String("oidc-issuer-url", "", "The URL of the OpenID Connect issuer")
216-
cmd.Flags().String("oidc-client-id", "", "The client ID for the OpenID Connect client")
217-
cmd.Flags().String("oidc-client-secret", "", "The client secret to use with OpenID Connect issuer")
218-
cmd.Flags().String("oidc-redirect-url", "", "The OAuth2 redirect URL")
219-
cmd.Flags().Duration("oidc-token-duration", time.Hour, "The duration of the ID token. It should be set in the format: number + time unit (s,m,h) e.g., 20m")
220-
cmd.Flags().String("oidc-claim-username", "", "JWT claim to use as the user name. By default email, which is expected to be a unique identifier of the end user. Admins can choose other claims, such as sub or name, depending on their provider")
221-
cmd.Flags().String("oidc-claim-groups", "", "JWT claim to use as the user's group. If the claim is present it must be an array of strings")
222-
cmd.Flags().StringSlice("custom-oidc-scopes", auth.DefaultScopes, "Customise the requested scopes for then OIDC authentication flow - openid will always be requested")
223-
224-
cmd.Flags().Bool("dev-mode", false, "starts the server in development mode")
225-
cmd.Flags().Bool("use-k8s-cached-clients", true, "Enables the use of cached clients")
226-
cmd.Flags().String("cost-estimation-filters", "", "Cost estimation filters")
227-
cmd.Flags().String("cost-estimation-api-region", "", "API region for cost estimation queries")
228-
cmd.Flags().String("ui-config", "", "UI configuration, JSON encoded")
229-
cmd.Flags().String("pipeline-controller-address", pipelines.DefaultPipelineControllerAddress, "Pipeline controller address")
230-
231-
// Hide some flags from the help output
232-
err := cmd.Flags().MarkHidden("cost-estimation-filters")
233-
if err != nil {
234-
log.Error(err, "error marking cost-estimation-filters flag as hidden")
235-
}
236-
err = cmd.Flags().MarkHidden("cost-estimation-api-region")
237-
if err != nil {
238-
log.Error(err, "error marking cost-estimation-api-region flag as hidden")
239-
}
191+
cmdFlags.String("entitlement-secret-name", ent.DefaultSecretName, "The name of the entitlement secret")
192+
cmdFlags.String("entitlement-secret-namespace", "flux-system", "The namespace of the entitlement secret")
193+
cmdFlags.String("helm-repo-namespace", os.Getenv("RUNTIME_NAMESPACE"), "the namespace of the Helm Repository resource to scan for profiles")
194+
cmdFlags.String("helm-repo-name", "weaveworks-charts", "the name of the Helm Repository resource to scan for profiles")
195+
cmdFlags.String("profile-cache-location", "/tmp/helm-cache", "the location where the cache Profile data lives")
196+
cmdFlags.String("html-root-path", "/html", "Where to serve static assets from")
197+
cmdFlags.String("git-provider-type", "", "")
198+
cmdFlags.String("git-provider-hostname", "", "")
199+
cmdFlags.Bool("capi-enabled", true, "")
200+
cmdFlags.String("capi-clusters-namespace", corev1.NamespaceAll, "where to look for GitOps cluster resources, defaults to looking in all namespaces")
201+
cmdFlags.String("capi-templates-namespace", "", "where to look for CAPI template resources, required")
202+
cmdFlags.String("inject-prune-annotation", "", "")
203+
cmdFlags.String("add-bases-kustomization", "enabled", "Add a kustomization to point to ./bases when creating leaf clusters")
204+
cmdFlags.String("capi-templates-repository-url", "", "")
205+
cmdFlags.String("capi-repository-path", "", "")
206+
cmdFlags.String("capi-repository-clusters-path", "./clusters", "")
207+
cmdFlags.String("capi-templates-repository-api-url", "", "")
208+
cmdFlags.String("capi-templates-repository-base-branch", "", "")
209+
cmdFlags.String("runtime-namespace", "flux-system", "Namespace hosting Gitops configuration objects (e.g. cluster-user-auth secrets)")
210+
cmdFlags.String("git-provider-token", "", "")
211+
cmdFlags.String("tls-cert-file", "", "filename for the TLS certficate, in-memory generated if omitted")
212+
cmdFlags.String("tls-private-key", "", "filename for the TLS key, in-memory generated if omitted")
213+
cmdFlags.Bool("no-tls", false, "do not attempt to read TLS certificates")
214+
cmdFlags.String("cluster-name", "management", "name of the management cluster")
215+
216+
cmdFlags.StringSlice("auth-methods", []string{"oidc", "token-passthrough", "user-account"}, "Which auth methods to use, valid values are 'oidc', 'token-pass-through' and 'user-account'")
217+
cmdFlags.String("oidc-issuer-url", "", "The URL of the OpenID Connect issuer")
218+
cmdFlags.String("oidc-client-id", "", "The client ID for the OpenID Connect client")
219+
cmdFlags.String("oidc-client-secret", "", "The client secret to use with OpenID Connect issuer")
220+
cmdFlags.String("oidc-redirect-url", "", "The OAuth2 redirect URL")
221+
cmdFlags.Duration("oidc-token-duration", time.Hour, "The duration of the ID token. It should be set in the format: number + time unit (s,m,h) e.g., 20m")
222+
cmdFlags.String("oidc-claim-username", "", "JWT claim to use as the user name. By default email, which is expected to be a unique identifier of the end user. Admins can choose other claims, such as sub or name, depending on their provider")
223+
cmdFlags.String("oidc-claim-groups", "", "JWT claim to use as the user's group. If the claim is present it must be an array of strings")
224+
cmdFlags.StringSlice("custom-oidc-scopes", auth.DefaultScopes, "Customise the requested scopes for then OIDC authentication flow - openid will always be requested")
225+
226+
cmdFlags.Bool("dev-mode", false, "starts the server in development mode")
227+
cmdFlags.Bool("use-k8s-cached-clients", true, "Enables the use of cached clients")
228+
cmdFlags.String("ui-config", "", "UI configuration, JSON encoded")
229+
cmdFlags.String("pipeline-controller-address", pipelines.DefaultPipelineControllerAddress, "Pipeline controller address")
230+
231+
cmdFlags.String("cost-estimation-filters", "", "Cost estimation filters")
232+
cmdFlags.String("cost-estimation-api-region", "", "API region for cost estimation queries")
233+
cmdFlags.String("cost-estimation-csv-file", "", "Filename to parse as Cost Estimation data")
234+
235+
cmdFlags.VisitAll(func(fl *flag.Flag) {
236+
if strings.HasPrefix(fl.Name, "cost-estimation") {
237+
cobra.CheckErr(cmdFlags.MarkHidden(fl.Name))
238+
}
239+
})
240240

241241
return cmd
242242
}
@@ -401,16 +401,21 @@ func StartServer(ctx context.Context, log logr.Logger, tempDir string, p Params)
401401
return fmt.Errorf("could not parse auth methods: %w", err)
402402
}
403403

404-
runtimeUtil.Must(capiv1.AddToScheme(clustersManagerScheme))
405-
runtimeUtil.Must(pacv2beta1.AddToScheme(clustersManagerScheme))
406-
runtimeUtil.Must(pacv2beta2.AddToScheme(clustersManagerScheme))
407-
runtimeUtil.Must(esv1beta1.AddToScheme(clustersManagerScheme))
408-
runtimeUtil.Must(flaggerv1beta1.AddToScheme(clustersManagerScheme))
409-
runtimeUtil.Must(pipelinev1alpha1.AddToScheme(clustersManagerScheme))
410-
runtimeUtil.Must(tfctrl.AddToScheme(clustersManagerScheme))
411-
runtimeUtil.Must(gitopsv1alpha1.AddToScheme(clustersManagerScheme))
412-
runtimeUtil.Must(clusterv1.AddToScheme(clustersManagerScheme))
413-
runtimeUtil.Must(gapiv1.AddToScheme(clustersManagerScheme))
404+
builder := runtime.NewSchemeBuilder(
405+
capiv1.AddToScheme,
406+
pacv2beta1.AddToScheme,
407+
pacv2beta2.AddToScheme,
408+
esv1beta1.AddToScheme,
409+
flaggerv1beta1.AddToScheme,
410+
pipelinev1alpha1.AddToScheme,
411+
tfctrl.AddToScheme,
412+
gitopsv1alpha1.AddToScheme,
413+
clusterv1.AddToScheme,
414+
gapiv1.AddToScheme,
415+
)
416+
if err := builder.AddToScheme(clustersManagerScheme); err != nil {
417+
return err
418+
}
414419

415420
mgmtCluster, err := cluster.NewSingleCluster(p.Cluster, rest, clustersManagerScheme, cluster.DefaultKubeConfigOptions...)
416421
if err != nil {
@@ -463,25 +468,11 @@ func StartServer(ctx context.Context, log logr.Logger, tempDir string, p Params)
463468
var estimator estimation.Estimator
464469
if featureflags.Get("WEAVE_GITOPS_FEATURE_COST_ESTIMATION") != "" {
465470
log.Info("Cost estimation feature flag is enabled")
466-
if p.CostEstimationFilters == "" {
467-
return fmt.Errorf("cost estimation filters cannot be empty")
468-
}
469-
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(p.CostEstimationAPIRegion))
471+
est, err := makeCostEstimator(ctx, log, p)
470472
if err != nil {
471-
log.Error(err, "unable to load AWS SDK config, cost estimation will not be available")
472-
} else {
473-
svc := pricing.NewFromConfig(cfg)
474-
pricer := estimation.NewAWSPricer(log, svc)
475-
476-
log.Info("Setting default cost estimation filters", "filters", p.CostEstimationFilters)
477-
filters, err := estimation.ParseFilterQueryString(p.CostEstimationFilters)
478-
if err != nil {
479-
return fmt.Errorf("could not parse cost estimation filters: %w", err)
480-
}
481-
log.Info("Parsed default cost estimation filters", "filters", filters)
482-
483-
estimator = estimation.NewAWSClusterEstimator(pricer, filters)
473+
return err
484474
}
475+
estimator = est
485476
}
486477

487478
coreCfg, err := core_core.NewCoreConfig(
@@ -973,3 +964,34 @@ func (fs *spaFileSystem) Open(name string) (http.File, error) {
973964
}
974965
return f, err
975966
}
967+
968+
func makeCostEstimator(ctx context.Context, log logr.Logger, p Params) (estimation.Estimator, error) {
969+
var pricer estimation.Pricer
970+
if p.CostEstimationFilename != "" {
971+
log.Info("configuring cost estimation from CSV", "filename", p.CostEstimationFilename)
972+
pr, err := estimation.NewCSVPricerFromFile(log, p.CostEstimationFilename)
973+
if err != nil {
974+
return nil, err
975+
}
976+
pricer = pr
977+
} else {
978+
if p.CostEstimationFilters == "" {
979+
return nil, errors.New("cost estimation filters cannot be empty")
980+
}
981+
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(p.CostEstimationAPIRegion))
982+
if err != nil {
983+
log.Error(err, "unable to load AWS SDK config, cost estimation will not be available")
984+
} else {
985+
svc := pricing.NewFromConfig(cfg)
986+
pricer = estimation.NewAWSPricer(log, svc)
987+
}
988+
}
989+
log.Info("Setting default cost estimation filters", "filters", p.CostEstimationFilters)
990+
filters, err := estimation.ParseFilterQueryString(p.CostEstimationFilters)
991+
if err != nil {
992+
return nil, fmt.Errorf("could not parse cost estimation filters: %w", err)
993+
}
994+
log.Info("Parsed default cost estimation filters", "filters", filters)
995+
996+
return estimation.NewAWSClusterEstimator(pricer, filters), nil
997+
}

0 commit comments

Comments
 (0)