Allow passing multiple `--config` flags to daprd in standalone mode

Spin-off from #6101 where support for Kubernetes mode has been dropped, to avoid modifying the CRDs.

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
ItalyPaleAle 2023-06-29 21:12:48 +00:00
parent 46813f2fd2
commit 1e268507d1
36 changed files with 963 additions and 493 deletions

View File

@ -135,6 +135,7 @@ linters-settings:
- "github.com/cenkalti/backoff/v3": "must use github.com/cenkalti/backoff/v4" - "github.com/cenkalti/backoff/v3": "must use github.com/cenkalti/backoff/v4"
- "github.com/benbjohnson/clock": "must use k8s.io/utils/clock" - "github.com/benbjohnson/clock": "must use k8s.io/utils/clock"
- "github.com/ghodss/yaml": "must use sigs.k8s.io/yaml" - "github.com/ghodss/yaml": "must use sigs.k8s.io/yaml"
- "gopkg.in/yaml.v2": "must use gopkg.in/yaml.v3"
misspell: misspell:
# Correct spellings using locale preferences for US or UK. # Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English. # Default is to use a neutral variety of English.

View File

@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.9.2 controller-gen.kubebuilder.io/version: v0.11.3
creationTimestamp: null creationTimestamp: null
name: configurations.dapr.io name: configurations.dapr.io
labels: labels:

View File

@ -74,8 +74,8 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
log.Infof("starting Dapr Runtime -- version %s -- commit %s", buildinfo.Version(), buildinfo.Commit()) log.Infof("Starting Dapr Runtime -- version %s -- commit %s", buildinfo.Version(), buildinfo.Commit())
log.Infof("log level set to: %s", opts.Logger.OutputLevel) log.Infof("Log level set to: %s", opts.Logger.OutputLevel)
rt, err := runtime.FromConfig(&runtime.Config{ rt, err := runtime.FromConfig(&runtime.Config{
AppID: opts.AppID, AppID: opts.AppID,
@ -108,7 +108,7 @@ func main() {
AppHealthThreshold: opts.AppHealthThreshold, AppHealthThreshold: opts.AppHealthThreshold,
AppChannelAddress: opts.AppChannelAddress, AppChannelAddress: opts.AppChannelAddress,
EnableAPILogging: opts.EnableAPILogging, EnableAPILogging: opts.EnableAPILogging,
ConfigPath: opts.ConfigPath, Config: opts.Config,
Metrics: opts.Metrics, Metrics: opts.Metrics,
AppSSL: opts.AppSSL, AppSSL: opts.AppSSL,
ComponentsPath: opts.ComponentsPath, ComponentsPath: opts.ComponentsPath,

View File

@ -14,7 +14,6 @@ limitations under the License.
package options package options
import ( import (
"errors"
"flag" "flag"
"strconv" "strconv"
"strings" "strings"
@ -61,7 +60,7 @@ type Options struct {
AppHealthThreshold int AppHealthThreshold int
EnableAppHealthCheck bool EnableAppHealthCheck bool
Mode string Mode string
ConfigPath string Config stringSliceFlag
UnixDomainSocket string UnixDomainSocket string
DaprHTTPReadBufferSize int DaprHTTPReadBufferSize int
DisableBuiltinK8sSecretStore bool DisableBuiltinK8sSecretStore bool
@ -87,7 +86,7 @@ func New(args []string) *Options {
flag.StringVar(&opts.AppProtocol, "app-protocol", string(protocol.HTTPProtocol), "Protocol for the application: grpc, grpcs, http, https, h2c") flag.StringVar(&opts.AppProtocol, "app-protocol", string(protocol.HTTPProtocol), "Protocol for the application: grpc, grpcs, http, https, h2c")
flag.StringVar(&opts.ComponentsPath, "components-path", "", "Alias for --resources-path [Deprecated, use --resources-path]") flag.StringVar(&opts.ComponentsPath, "components-path", "", "Alias for --resources-path [Deprecated, use --resources-path]")
flag.Var(&opts.ResourcesPath, "resources-path", "Path for resources directory. If not specified, no resources will be loaded. Can be passed multiple times") flag.Var(&opts.ResourcesPath, "resources-path", "Path for resources directory. If not specified, no resources will be loaded. Can be passed multiple times")
flag.StringVar(&opts.ConfigPath, "config", "", "Path to config file, or name of a configuration object") flag.Var(&opts.Config, "config", "Path to config file, or name of a configuration object. In standalone mode, can be passed multiple times")
flag.StringVar(&opts.AppID, "app-id", "", "A unique ID for Dapr. Used for Service Discovery and state") flag.StringVar(&opts.AppID, "app-id", "", "A unique ID for Dapr. Used for Service Discovery and state")
flag.StringVar(&opts.ControlPlaneAddress, "control-plane-address", "", "Address for a Dapr control plane") flag.StringVar(&opts.ControlPlaneAddress, "control-plane-address", "", "Address for a Dapr control plane")
flag.StringVar(&opts.SentryAddress, "sentry-address", "", "Address for the Sentry CA service") flag.StringVar(&opts.SentryAddress, "sentry-address", "", "Address for the Sentry CA service")
@ -151,7 +150,7 @@ func (f stringSliceFlag) String() string {
// Set the flag value. // Set the flag value.
func (f *stringSliceFlag) Set(value string) error { func (f *stringSliceFlag) Set(value string) error {
if value == "" { if value == "" {
return errors.New("value is empty") return nil
} }
*f = append(*f, value) *f = append(*f, value)
return nil return nil

View File

@ -40,5 +40,5 @@ func TestStandaloneGlobalConfig(t *testing.T) {
opts := New([]string{"--app-id", "testapp", "--mode", string(modes.StandaloneMode), "--config", "../../../pkg/config/testdata/metric_disabled.yaml", "--metrics-port", strconv.Itoa(10000)}) opts := New([]string{"--app-id", "testapp", "--mode", string(modes.StandaloneMode), "--config", "../../../pkg/config/testdata/metric_disabled.yaml", "--metrics-port", strconv.Itoa(10000)})
assert.EqualValues(t, "testapp", opts.AppID) assert.EqualValues(t, "testapp", opts.AppID)
assert.EqualValues(t, string(modes.StandaloneMode), opts.Mode) assert.EqualValues(t, string(modes.StandaloneMode), opts.Mode)
assert.Equal(t, "../../../pkg/config/testdata/metric_disabled.yaml", opts.ConfigPath) assert.Equal(t, []string{"../../../pkg/config/testdata/metric_disabled.yaml"}, []string(opts.Config))
} }

4
go.mod
View File

@ -62,7 +62,7 @@ require (
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
google.golang.org/grpc v1.54.0 google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.30.0 google.golang.org/protobuf v1.30.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.26.3 k8s.io/api v0.26.3
k8s.io/apiextensions-apiserver v0.26.3 k8s.io/apiextensions-apiserver v0.26.3
k8s.io/apimachinery v0.26.3 k8s.io/apimachinery v0.26.3
@ -399,7 +399,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/component-base v0.26.3 // indirect k8s.io/component-base v0.26.3 // indirect
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
k8s.io/klog/v2 v2.80.1 // indirect k8s.io/klog/v2 v2.80.1 // indirect

View File

@ -35,25 +35,26 @@ import (
var log = logger.NewLogger("dapr.acl") var log = logger.NewLogger("dapr.acl")
// ParseAccessControlSpec creates an in-memory copy of the Access Control Spec for fast lookup. // ParseAccessControlSpec creates an in-memory copy of the Access Control Spec for fast lookup.
func ParseAccessControlSpec(accessControlSpec config.AccessControlSpec, isHTTP bool) (*config.AccessControlList, error) { func ParseAccessControlSpec(accessControlSpec *config.AccessControlSpec, isHTTP bool) (*config.AccessControlList, error) {
if accessControlSpec.TrustDomain == "" && if accessControlSpec == nil ||
accessControlSpec.DefaultAction == "" && (accessControlSpec.TrustDomain == "" &&
(accessControlSpec.AppPolicies == nil || len(accessControlSpec.AppPolicies) == 0) { accessControlSpec.DefaultAction == "" &&
len(accessControlSpec.AppPolicies) == 0) {
// No ACL has been specified // No ACL has been specified
log.Debugf("No Access control policy specified") log.Debugf("No Access control policy specified")
return nil, nil return nil, nil
} }
var accessControlList config.AccessControlList accessControlList := config.AccessControlList{
accessControlList.PolicySpec = make(map[string]config.AccessControlListPolicySpec) PolicySpec: make(map[string]config.AccessControlListPolicySpec),
accessControlList.DefaultAction = strings.ToLower(accessControlSpec.DefaultAction) DefaultAction: strings.ToLower(accessControlSpec.DefaultAction),
TrustDomain: accessControlSpec.TrustDomain,
}
accessControlList.TrustDomain = accessControlSpec.TrustDomain
if accessControlSpec.TrustDomain == "" { if accessControlSpec.TrustDomain == "" {
accessControlList.TrustDomain = config.DefaultTrustDomain accessControlList.TrustDomain = config.DefaultTrustDomain
} }
accessControlList.DefaultAction = accessControlSpec.DefaultAction
if accessControlSpec.DefaultAction == "" { if accessControlSpec.DefaultAction == "" {
if accessControlSpec.AppPolicies == nil || len(accessControlSpec.AppPolicies) > 0 { if accessControlSpec.AppPolicies == nil || len(accessControlSpec.AppPolicies) > 0 {
// Some app level policies have been specified but not default global action is set. Default to more secure option - Deny // Some app level policies have been specified but not default global action is set. Default to more secure option - Deny

View File

@ -18,6 +18,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/dapr/dapr/pkg/config" "github.com/dapr/dapr/pkg/config"
"github.com/dapr/dapr/pkg/proto/common/v1" "github.com/dapr/dapr/pkg/proto/common/v1"
@ -130,7 +131,7 @@ func initializeAccessControlList(isHTTP bool) (*config.AccessControlList, error)
}, },
}, },
} }
accessControlList, err := ParseAccessControlSpec(inputSpec, isHTTP) accessControlList, err := ParseAccessControlSpec(&inputSpec, isHTTP)
return accessControlList, err return accessControlList, err
} }
@ -139,7 +140,7 @@ func TestParseAccessControlSpec(t *testing.T) {
t.Run("translate to in-memory rules", func(t *testing.T) { t.Run("translate to in-memory rules", func(t *testing.T) {
accessControlList, err := initializeAccessControlList(true) accessControlList, err := initializeAccessControlList(true)
assert.Nil(t, err) require.NoError(t, err)
assert.Equal(t, config.DenyAccess, accessControlList.DefaultAction) assert.Equal(t, config.DenyAccess, accessControlList.DefaultAction)
assert.Equal(t, "abcd", accessControlList.TrustDomain) assert.Equal(t, "abcd", accessControlList.TrustDomain)
@ -237,7 +238,7 @@ func TestParseAccessControlSpec(t *testing.T) {
}) })
t.Run("test when no trust domain and namespace specified in app policy", func(t *testing.T) { t.Run("test when no trust domain and namespace specified in app policy", func(t *testing.T) {
invalidAccessControlSpec := config.AccessControlSpec{ invalidAccessControlSpec := &config.AccessControlSpec{
DefaultAction: config.DenyAccess, DefaultAction: config.DenyAccess,
TrustDomain: "public", TrustDomain: "public",
AppPolicies: []config.AppPolicySpec{ AppPolicies: []config.AppPolicySpec{
@ -300,7 +301,7 @@ func TestParseAccessControlSpec(t *testing.T) {
}) })
t.Run("test when no trust domain is specified for the app", func(t *testing.T) { t.Run("test when no trust domain is specified for the app", func(t *testing.T) {
accessControlSpec := config.AccessControlSpec{ accessControlSpec := &config.AccessControlSpec{
DefaultAction: config.DenyAccess, DefaultAction: config.DenyAccess,
TrustDomain: "", TrustDomain: "",
AppPolicies: []config.AppPolicySpec{ AppPolicies: []config.AppPolicySpec{
@ -330,18 +331,23 @@ func TestParseAccessControlSpec(t *testing.T) {
}) })
t.Run("test when no access control policy has been specified", func(t *testing.T) { t.Run("test when no access control policy has been specified", func(t *testing.T) {
invalidAccessControlSpec := config.AccessControlSpec{ accessControlList, err := ParseAccessControlSpec(nil, true)
require.NoError(t, err)
assert.Nil(t, accessControlList)
invalidAccessControlSpec := &config.AccessControlSpec{
DefaultAction: "", DefaultAction: "",
TrustDomain: "", TrustDomain: "",
AppPolicies: []config.AppPolicySpec{}, AppPolicies: []config.AppPolicySpec{},
} }
accessControlList, _ := ParseAccessControlSpec(invalidAccessControlSpec, true) accessControlList, _ = ParseAccessControlSpec(invalidAccessControlSpec, true)
require.NoError(t, err)
assert.Nil(t, accessControlList) assert.Nil(t, accessControlList)
}) })
t.Run("test when no default global action has been specified", func(t *testing.T) { t.Run("test when no default global action has been specified", func(t *testing.T) {
invalidAccessControlSpec := config.AccessControlSpec{ invalidAccessControlSpec := &config.AccessControlSpec{
TrustDomain: "public", TrustDomain: "public",
AppPolicies: []config.AppPolicySpec{ AppPolicies: []config.AppPolicySpec{
{ {
@ -377,25 +383,25 @@ func TestSpiffeID(t *testing.T) {
assert.Equal(t, "mydomain", id.TrustDomain) assert.Equal(t, "mydomain", id.TrustDomain)
assert.Equal(t, "mynamespace", id.Namespace) assert.Equal(t, "mynamespace", id.Namespace)
assert.Equal(t, "myappid", id.AppID) assert.Equal(t, "myappid", id.AppID)
assert.Nil(t, err) require.NoError(t, err)
}) })
t.Run("test parse invalid spiffe id", func(t *testing.T) { t.Run("test parse invalid spiffe id", func(t *testing.T) {
spiffeID := "abcd" spiffeID := "abcd"
_, err := parseSpiffeID(spiffeID) _, err := parseSpiffeID(spiffeID)
assert.NotNil(t, err) require.Error(t, err)
}) })
t.Run("test parse spiffe id with not all fields", func(t *testing.T) { t.Run("test parse spiffe id with not all fields", func(t *testing.T) {
spiffeID := "spiffe://mydomain/ns/myappid" spiffeID := "spiffe://mydomain/ns/myappid"
_, err := parseSpiffeID(spiffeID) _, err := parseSpiffeID(spiffeID)
assert.NotNil(t, err) require.Error(t, err)
}) })
t.Run("test empty spiffe id", func(t *testing.T) { t.Run("test empty spiffe id", func(t *testing.T) {
spiffeID := "" spiffeID := ""
_, err := parseSpiffeID(spiffeID) _, err := parseSpiffeID(spiffeID)
assert.NotNil(t, err) require.Error(t, err)
}) })
} }

View File

@ -36,31 +36,31 @@ type Configuration struct {
// ConfigurationSpec is the spec for an configuration. // ConfigurationSpec is the spec for an configuration.
type ConfigurationSpec struct { type ConfigurationSpec struct {
// +optional // +optional
AppHTTPPipelineSpec PipelineSpec `json:"appHttpPipeline,omitempty"` AppHTTPPipelineSpec *PipelineSpec `json:"appHttpPipeline,omitempty"`
// +optional // +optional
HTTPPipelineSpec PipelineSpec `json:"httpPipeline,omitempty"` HTTPPipelineSpec *PipelineSpec `json:"httpPipeline,omitempty"`
// +optional // +optional
TracingSpec TracingSpec `json:"tracing,omitempty"` TracingSpec *TracingSpec `json:"tracing,omitempty"`
// +kubebuilder:default={enabled:true} // +kubebuilder:default={enabled:true}
MetricSpec MetricSpec `json:"metric,omitempty"` MetricSpec *MetricSpec `json:"metric,omitempty"`
// +kubebuilder:default={enabled:true} // +kubebuilder:default={enabled:true}
MetricsSpec MetricSpec `json:"metrics,omitempty"` MetricsSpec *MetricSpec `json:"metrics,omitempty"`
// +optional // +optional
MTLSSpec MTLSSpec `json:"mtls,omitempty"` MTLSSpec *MTLSSpec `json:"mtls,omitempty"`
// +optional // +optional
Secrets SecretsSpec `json:"secrets,omitempty"` Secrets *SecretsSpec `json:"secrets,omitempty"`
// +optional // +optional
AccessControlSpec AccessControlSpec `json:"accessControl,omitempty"` AccessControlSpec *AccessControlSpec `json:"accessControl,omitempty"`
// +optional // +optional
NameResolutionSpec NameResolutionSpec `json:"nameResolution,omitempty"` NameResolutionSpec *NameResolutionSpec `json:"nameResolution,omitempty"`
// +optional // +optional
Features []FeatureSpec `json:"features,omitempty"` Features []FeatureSpec `json:"features,omitempty"`
// +optional // +optional
APISpec APISpec `json:"api,omitempty"` APISpec *APISpec `json:"api,omitempty"`
// +optional // +optional
ComponentsSpec ComponentsSpec `json:"components,omitempty"` ComponentsSpec *ComponentsSpec `json:"components,omitempty"`
// +optional // +optional
LoggingSpec LoggingSpec `json:"logging,omitempty"` LoggingSpec *LoggingSpec `json:"logging,omitempty"`
} }
// APISpec describes the configuration for Dapr APIs. // APISpec describes the configuration for Dapr APIs.
@ -78,14 +78,14 @@ type APIAccessRule struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
// +optional // +optional
Protocol string `json:"protocol"` Protocol string `json:"protocol,omitempty"`
} }
// NameResolutionSpec is the spec for name resolution configuration. // NameResolutionSpec is the spec for name resolution configuration.
type NameResolutionSpec struct { type NameResolutionSpec struct {
Component string `json:"component"` Component string `json:"component"`
Version string `json:"version"` Version string `json:"version"`
Configuration DynamicValue `json:"configuration"` Configuration *DynamicValue `json:"configuration"`
} }
// SecretsSpec is the spec for secrets configuration. // SecretsSpec is the spec for secrets configuration.
@ -95,9 +95,9 @@ type SecretsSpec struct {
// SecretsScope defines the scope for secrets. // SecretsScope defines the scope for secrets.
type SecretsScope struct { type SecretsScope struct {
StoreName string `json:"storeName"`
// +optional // +optional
DefaultAccess string `json:"defaultAccess,omitempty"` DefaultAccess string `json:"defaultAccess,omitempty"`
StoreName string `json:"storeName"`
// +optional // +optional
AllowedSecrets []string `json:"allowedSecrets,omitempty"` AllowedSecrets []string `json:"allowedSecrets,omitempty"`
// +optional // +optional
@ -111,18 +111,25 @@ type PipelineSpec struct {
// HandlerSpec defines a request handlers. // HandlerSpec defines a request handlers.
type HandlerSpec struct { type HandlerSpec struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
SelectorSpec SelectorSpec `json:"selector,omitempty"` // +optional
SelectorSpec *SelectorSpec `json:"selector,omitempty"`
} }
// MTLSSpec defines mTLS configuration. // MTLSSpec defines mTLS configuration.
type MTLSSpec struct { type MTLSSpec struct {
Enabled bool `json:"enabled"` Enabled *bool `json:"enabled"`
// +optional // +optional
WorkloadCertTTL string `json:"workloadCertTTL"` WorkloadCertTTL *string `json:"workloadCertTTL,omitempty"`
// +optional // +optional
AllowedClockSkew string `json:"allowedClockSkew"` AllowedClockSkew *string `json:"allowedClockSkew,omitempty"`
}
// GetEnabled returns true if mTLS is enabled.
func (m *MTLSSpec) GetEnabled() bool {
// Defaults to true if unset
return m == nil || m.Enabled == nil || *m.Enabled
} }
// SelectorSpec selects target services to which the handler is to be applied. // SelectorSpec selects target services to which the handler is to be applied.
@ -140,18 +147,18 @@ type SelectorField struct {
type TracingSpec struct { type TracingSpec struct {
SamplingRate string `json:"samplingRate"` SamplingRate string `json:"samplingRate"`
// +optional // +optional
Stdout bool `json:"stdout"` Stdout *bool `json:"stdout,omitempty"`
// +optional // +optional
Zipkin ZipkinSpec `json:"zipkin"` Zipkin *ZipkinSpec `json:"zipkin,omitempty"`
// +optional // +optional
Otel OtelSpec `json:"otel"` Otel *OtelSpec `json:"otel,omitempty"`
} }
// OtelSpec defines Otel exporter configurations. // OtelSpec defines Otel exporter configurations.
type OtelSpec struct { type OtelSpec struct {
Protocol string `json:"protocol" yaml:"protocol"` Protocol string `json:"protocol" yaml:"protocol"`
EndpointAddress string `json:"endpointAddress" yaml:"endpointAddress"` EndpointAddress string `json:"endpointAddress" yaml:"endpointAddress"`
IsSecure bool `json:"isSecure" yaml:"isSecure"` IsSecure *bool `json:"isSecure" yaml:"isSecure"`
} }
// ZipkinSpec defines Zipkin trace configurations. // ZipkinSpec defines Zipkin trace configurations.
@ -161,9 +168,9 @@ type ZipkinSpec struct {
// MetricSpec defines metrics configuration. // MetricSpec defines metrics configuration.
type MetricSpec struct { type MetricSpec struct {
Enabled bool `json:"enabled"` Enabled *bool `json:"enabled"`
// +optional // +optional
Rules []MetricsRule `json:"rules"` Rules []MetricsRule `json:"rules,omitempty"`
} }
// MetricsRule defines configuration options for a metric. // MetricsRule defines configuration options for a metric.
@ -182,37 +189,37 @@ type MetricLabel struct {
type AppPolicySpec struct { type AppPolicySpec struct {
AppName string `json:"appId" yaml:"appId"` AppName string `json:"appId" yaml:"appId"`
// +optional // +optional
DefaultAction string `json:"defaultAction" yaml:"defaultAction"` DefaultAction string `json:"defaultAction,omitempty" yaml:"defaultAction,omitempty"`
// +optional // +optional
TrustDomain string `json:"trustDomain" yaml:"trustDomain"` TrustDomain string `json:"trustDomain,omitempty" yaml:"trustDomain,omitempty"`
// +optional // +optional
Namespace string `json:"namespace" yaml:"namespace"` Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
// +optional // +optional
AppOperationActions []AppOperationAction `json:"operations" yaml:"operations"` AppOperationActions []AppOperationAction `json:"operations,omitempty" yaml:"operations,omitempty"`
} }
// AppOperationAction defines the data structure for each app operation. // AppOperationAction defines the data structure for each app operation.
type AppOperationAction struct { type AppOperationAction struct {
Operation string `json:"name" yaml:"name"` Operation string `json:"name" yaml:"name"`
Action string `json:"action" yaml:"action"`
// +optional // +optional
HTTPVerb []string `json:"httpVerb" yaml:"httpVerb"` HTTPVerb []string `json:"httpVerb,omitempty" yaml:"httpVerb,omitempty"`
Action string `json:"action" yaml:"action"`
} }
// AccessControlSpec is the spec object in ConfigurationSpec. // AccessControlSpec is the spec object in ConfigurationSpec.
type AccessControlSpec struct { type AccessControlSpec struct {
// +optional // +optional
DefaultAction string `json:"defaultAction" yaml:"defaultAction"` DefaultAction string `json:"defaultAction,omitempty" yaml:"defaultAction,omitempty"`
// +optional // +optional
TrustDomain string `json:"trustDomain" yaml:"trustDomain"` TrustDomain string `json:"trustDomain,omitempty" yaml:"trustDomain,omitempty"`
// +optional // +optional
AppPolicies []AppPolicySpec `json:"policies" yaml:"policies"` AppPolicies []AppPolicySpec `json:"policies,omitempty" yaml:"policies,omitempty"`
} }
// FeatureSpec defines the features that are enabled/disabled. // FeatureSpec defines the features that are enabled/disabled.
type FeatureSpec struct { type FeatureSpec struct {
Name string `json:"name" yaml:"name"` Name string `json:"name" yaml:"name"`
Enabled bool `json:"enabled" yaml:"enabled"` Enabled *bool `json:"enabled" yaml:"enabled"`
} }
// ComponentsSpec describes the configuration for Dapr components // ComponentsSpec describes the configuration for Dapr components
@ -222,6 +229,30 @@ type ComponentsSpec struct {
Deny []string `json:"deny,omitempty" yaml:"deny,omitempty"` Deny []string `json:"deny,omitempty" yaml:"deny,omitempty"`
} }
// LoggingSpec defines the configuration for logging.
type LoggingSpec struct {
// Configure API logging.
// +optional
APILogging *APILoggingSpec `json:"apiLogging,omitempty" yaml:"apiLogging,omitempty"`
}
// APILoggingSpec defines the configuration for API logging.
type APILoggingSpec struct {
// Default value for enabling API logging. Sidecars can always override this by setting `--enable-api-logging` to true or false explicitly.
// The default value is false.
// +optional
Enabled *bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
// When enabled, obfuscates the values of URLs in HTTP API logs, logging the route name rather than the full path being invoked, which could contain PII.
// Default: false.
// This option has no effect if API logging is disabled.
// +optional
ObfuscateURLs *bool `json:"obfuscateURLs,omitempty" yaml:"obfuscateURLs,omitempty"`
// If true, health checks are not reported in API logs. Default: false.
// This option has no effect if API logging is disabled.
// +optional
OmitHealthChecks *bool `json:"omitHealthChecks,omitempty" yaml:"omitHealthChecks,omitempty"`
}
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// ConfigurationList is a list of Dapr event sources. // ConfigurationList is a list of Dapr event sources.
@ -232,30 +263,6 @@ type ConfigurationList struct {
Items []Configuration `json:"items"` Items []Configuration `json:"items"`
} }
// LoggingSpec defines the configuration for logging.
type LoggingSpec struct {
// Configure API logging.
// +optional
APILogging APILoggingSpec `json:"apiLogging" yaml:"apiLogging"`
}
// APILoggingSpec defines the configuration for API logging.
type APILoggingSpec struct {
// Default value for enabling API logging. Sidecars can always override this by setting `--enable-api-logging` to true or false explicitly.
// The default value is false.
// +optional
Enabled bool `json:"enabled" yaml:"enabled"`
// When enabled, obfuscates the values of URLs in HTTP API logs, logging the route name rather than the full path being invoked, which could contain PII.
// Default: false.
// This option has no effect if API logging is disabled.
// +optional
ObfuscateURLs bool `json:"obfuscateURLs" yaml:"obfuscateURLs"`
// If true, health checks are not reported in API logs. Default: false.
// This option has no effect if API logging is disabled.
// +optional
OmitHealthChecks bool `json:"omitHealthChecks" yaml:"omitHealthChecks"`
}
// DynamicValue is a dynamic value struct for the component.metadata pair value. // DynamicValue is a dynamic value struct for the component.metadata pair value.
type DynamicValue struct { type DynamicValue struct {
v1.JSON `json:",inline"` v1.JSON `json:",inline"`

View File

@ -43,6 +43,21 @@ func (in *APIAccessRule) DeepCopy() *APIAccessRule {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APILoggingSpec) DeepCopyInto(out *APILoggingSpec) { func (in *APILoggingSpec) DeepCopyInto(out *APILoggingSpec) {
*out = *in *out = *in
if in.Enabled != nil {
in, out := &in.Enabled, &out.Enabled
*out = new(bool)
**out = **in
}
if in.ObfuscateURLs != nil {
in, out := &in.ObfuscateURLs, &out.ObfuscateURLs
*out = new(bool)
**out = **in
}
if in.OmitHealthChecks != nil {
in, out := &in.OmitHealthChecks, &out.OmitHealthChecks
*out = new(bool)
**out = **in
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APILoggingSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APILoggingSpec.
@ -225,23 +240,73 @@ func (in *ConfigurationList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) { func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
*out = *in *out = *in
in.AppHTTPPipelineSpec.DeepCopyInto(&out.AppHTTPPipelineSpec) if in.AppHTTPPipelineSpec != nil {
in.HTTPPipelineSpec.DeepCopyInto(&out.HTTPPipelineSpec) in, out := &in.AppHTTPPipelineSpec, &out.AppHTTPPipelineSpec
out.TracingSpec = in.TracingSpec *out = new(PipelineSpec)
in.MetricSpec.DeepCopyInto(&out.MetricSpec) (*in).DeepCopyInto(*out)
in.MetricsSpec.DeepCopyInto(&out.MetricsSpec) }
out.MTLSSpec = in.MTLSSpec if in.HTTPPipelineSpec != nil {
in.Secrets.DeepCopyInto(&out.Secrets) in, out := &in.HTTPPipelineSpec, &out.HTTPPipelineSpec
in.AccessControlSpec.DeepCopyInto(&out.AccessControlSpec) *out = new(PipelineSpec)
in.NameResolutionSpec.DeepCopyInto(&out.NameResolutionSpec) (*in).DeepCopyInto(*out)
}
if in.TracingSpec != nil {
in, out := &in.TracingSpec, &out.TracingSpec
*out = new(TracingSpec)
(*in).DeepCopyInto(*out)
}
if in.MetricSpec != nil {
in, out := &in.MetricSpec, &out.MetricSpec
*out = new(MetricSpec)
(*in).DeepCopyInto(*out)
}
if in.MetricsSpec != nil {
in, out := &in.MetricsSpec, &out.MetricsSpec
*out = new(MetricSpec)
(*in).DeepCopyInto(*out)
}
if in.MTLSSpec != nil {
in, out := &in.MTLSSpec, &out.MTLSSpec
*out = new(MTLSSpec)
(*in).DeepCopyInto(*out)
}
if in.Secrets != nil {
in, out := &in.Secrets, &out.Secrets
*out = new(SecretsSpec)
(*in).DeepCopyInto(*out)
}
if in.AccessControlSpec != nil {
in, out := &in.AccessControlSpec, &out.AccessControlSpec
*out = new(AccessControlSpec)
(*in).DeepCopyInto(*out)
}
if in.NameResolutionSpec != nil {
in, out := &in.NameResolutionSpec, &out.NameResolutionSpec
*out = new(NameResolutionSpec)
(*in).DeepCopyInto(*out)
}
if in.Features != nil { if in.Features != nil {
in, out := &in.Features, &out.Features in, out := &in.Features, &out.Features
*out = make([]FeatureSpec, len(*in)) *out = make([]FeatureSpec, len(*in))
copy(*out, *in) for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.APISpec != nil {
in, out := &in.APISpec, &out.APISpec
*out = new(APISpec)
(*in).DeepCopyInto(*out)
}
if in.ComponentsSpec != nil {
in, out := &in.ComponentsSpec, &out.ComponentsSpec
*out = new(ComponentsSpec)
(*in).DeepCopyInto(*out)
}
if in.LoggingSpec != nil {
in, out := &in.LoggingSpec, &out.LoggingSpec
*out = new(LoggingSpec)
(*in).DeepCopyInto(*out)
} }
in.APISpec.DeepCopyInto(&out.APISpec)
in.ComponentsSpec.DeepCopyInto(&out.ComponentsSpec)
out.LoggingSpec = in.LoggingSpec
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec.
@ -273,6 +338,11 @@ func (in *DynamicValue) DeepCopy() *DynamicValue {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FeatureSpec) DeepCopyInto(out *FeatureSpec) { func (in *FeatureSpec) DeepCopyInto(out *FeatureSpec) {
*out = *in *out = *in
if in.Enabled != nil {
in, out := &in.Enabled, &out.Enabled
*out = new(bool)
**out = **in
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureSpec.
@ -288,7 +358,11 @@ func (in *FeatureSpec) DeepCopy() *FeatureSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HandlerSpec) DeepCopyInto(out *HandlerSpec) { func (in *HandlerSpec) DeepCopyInto(out *HandlerSpec) {
*out = *in *out = *in
in.SelectorSpec.DeepCopyInto(&out.SelectorSpec) if in.SelectorSpec != nil {
in, out := &in.SelectorSpec, &out.SelectorSpec
*out = new(SelectorSpec)
(*in).DeepCopyInto(*out)
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandlerSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandlerSpec.
@ -304,7 +378,11 @@ func (in *HandlerSpec) DeepCopy() *HandlerSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LoggingSpec) DeepCopyInto(out *LoggingSpec) { func (in *LoggingSpec) DeepCopyInto(out *LoggingSpec) {
*out = *in *out = *in
out.APILogging = in.APILogging if in.APILogging != nil {
in, out := &in.APILogging, &out.APILogging
*out = new(APILoggingSpec)
(*in).DeepCopyInto(*out)
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingSpec.
@ -320,6 +398,21 @@ func (in *LoggingSpec) DeepCopy() *LoggingSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MTLSSpec) DeepCopyInto(out *MTLSSpec) { func (in *MTLSSpec) DeepCopyInto(out *MTLSSpec) {
*out = *in *out = *in
if in.Enabled != nil {
in, out := &in.Enabled, &out.Enabled
*out = new(bool)
**out = **in
}
if in.WorkloadCertTTL != nil {
in, out := &in.WorkloadCertTTL, &out.WorkloadCertTTL
*out = new(string)
**out = **in
}
if in.AllowedClockSkew != nil {
in, out := &in.AllowedClockSkew, &out.AllowedClockSkew
*out = new(string)
**out = **in
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MTLSSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MTLSSpec.
@ -357,6 +450,11 @@ func (in *MetricLabel) DeepCopy() *MetricLabel {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MetricSpec) DeepCopyInto(out *MetricSpec) { func (in *MetricSpec) DeepCopyInto(out *MetricSpec) {
*out = *in *out = *in
if in.Enabled != nil {
in, out := &in.Enabled, &out.Enabled
*out = new(bool)
**out = **in
}
if in.Rules != nil { if in.Rules != nil {
in, out := &in.Rules, &out.Rules in, out := &in.Rules, &out.Rules
*out = make([]MetricsRule, len(*in)) *out = make([]MetricsRule, len(*in))
@ -401,7 +499,11 @@ func (in *MetricsRule) DeepCopy() *MetricsRule {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NameResolutionSpec) DeepCopyInto(out *NameResolutionSpec) { func (in *NameResolutionSpec) DeepCopyInto(out *NameResolutionSpec) {
*out = *in *out = *in
in.Configuration.DeepCopyInto(&out.Configuration) if in.Configuration != nil {
in, out := &in.Configuration, &out.Configuration
*out = new(DynamicValue)
(*in).DeepCopyInto(*out)
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameResolutionSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameResolutionSpec.
@ -417,6 +519,11 @@ func (in *NameResolutionSpec) DeepCopy() *NameResolutionSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OtelSpec) DeepCopyInto(out *OtelSpec) { func (in *OtelSpec) DeepCopyInto(out *OtelSpec) {
*out = *in *out = *in
if in.IsSecure != nil {
in, out := &in.IsSecure, &out.IsSecure
*out = new(bool)
**out = **in
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OtelSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OtelSpec.
@ -536,8 +643,21 @@ func (in *SelectorSpec) DeepCopy() *SelectorSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TracingSpec) DeepCopyInto(out *TracingSpec) { func (in *TracingSpec) DeepCopyInto(out *TracingSpec) {
*out = *in *out = *in
out.Zipkin = in.Zipkin if in.Stdout != nil {
out.Otel = in.Otel in, out := &in.Stdout, &out.Stdout
*out = new(bool)
**out = **in
}
if in.Zipkin != nil {
in, out := &in.Zipkin, &out.Zipkin
*out = new(ZipkinSpec)
**out = **in
}
if in.Otel != nil {
in, out := &in.Otel, &out.Otel
*out = new(OtelSpec)
(*in).DeepCopyInto(*out)
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracingSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracingSpec.

View File

@ -25,13 +25,14 @@ import (
env "github.com/dapr/dapr/pkg/config/env" env "github.com/dapr/dapr/pkg/config/env"
grpcRetry "github.com/grpc-ecosystem/go-grpc-middleware/retry" grpcRetry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"github.com/dapr/dapr/pkg/buildinfo" "github.com/dapr/dapr/pkg/buildinfo"
operatorv1pb "github.com/dapr/dapr/pkg/proto/operator/v1" operatorv1pb "github.com/dapr/dapr/pkg/proto/operator/v1"
"github.com/dapr/dapr/utils" "github.com/dapr/dapr/utils"
"github.com/dapr/kit/ptr"
) )
// Feature Flags section // Feature Flags section
@ -99,35 +100,35 @@ type AccessControlListOperationAction struct {
} }
type ConfigurationSpec struct { type ConfigurationSpec struct {
HTTPPipelineSpec PipelineSpec `json:"httpPipeline,omitempty" yaml:"httpPipeline,omitempty"` HTTPPipelineSpec *PipelineSpec `json:"httpPipeline,omitempty" yaml:"httpPipeline,omitempty"`
AppHTTPPipelineSpec PipelineSpec `json:"appHttpPipeline,omitempty" yaml:"appHttpPipeline,omitempty"` AppHTTPPipelineSpec *PipelineSpec `json:"appHttpPipeline,omitempty" yaml:"appHttpPipeline,omitempty"`
TracingSpec TracingSpec `json:"tracing,omitempty" yaml:"tracing,omitempty"` TracingSpec *TracingSpec `json:"tracing,omitempty" yaml:"tracing,omitempty"`
MTLSSpec MTLSSpec `json:"mtls,omitempty" yaml:"mtls,omitempty"` MTLSSpec *MTLSSpec `json:"mtls,omitempty" yaml:"mtls,omitempty"`
MetricSpec MetricSpec `json:"metric,omitempty" yaml:"metric,omitempty"` MetricSpec *MetricSpec `json:"metric,omitempty" yaml:"metric,omitempty"`
MetricsSpec MetricSpec `json:"metrics,omitempty" yaml:"metrics,omitempty"` MetricsSpec *MetricSpec `json:"metrics,omitempty" yaml:"metrics,omitempty"`
Secrets SecretsSpec `json:"secrets,omitempty" yaml:"secrets,omitempty"` Secrets *SecretsSpec `json:"secrets,omitempty" yaml:"secrets,omitempty"`
AccessControlSpec AccessControlSpec `json:"accessControl,omitempty" yaml:"accessControl,omitempty"` AccessControlSpec *AccessControlSpec `json:"accessControl,omitempty" yaml:"accessControl,omitempty"`
NameResolutionSpec NameResolutionSpec `json:"nameResolution,omitempty" yaml:"nameResolution,omitempty"` NameResolutionSpec *NameResolutionSpec `json:"nameResolution,omitempty" yaml:"nameResolution,omitempty"`
Features []FeatureSpec `json:"features,omitempty" yaml:"features,omitempty"` Features []FeatureSpec `json:"features,omitempty" yaml:"features,omitempty"`
APISpec APISpec `json:"api,omitempty" yaml:"api,omitempty"` APISpec *APISpec `json:"api,omitempty" yaml:"api,omitempty"`
ComponentsSpec ComponentsSpec `json:"components,omitempty" yaml:"components,omitempty"` ComponentsSpec *ComponentsSpec `json:"components,omitempty" yaml:"components,omitempty"`
LoggingSpec LoggingSpec `json:"logging,omitempty" yaml:"logging,omitempty"` LoggingSpec *LoggingSpec `json:"logging,omitempty" yaml:"logging,omitempty"`
} }
type SecretsSpec struct { type SecretsSpec struct {
Scopes []SecretsScope `json:"scopes"` Scopes []SecretsScope `json:"scopes,omitempty"`
} }
// SecretsScope defines the scope for secrets. // SecretsScope defines the scope for secrets.
type SecretsScope struct { type SecretsScope struct {
DefaultAccess string `json:"defaultAccess,omitempty" yaml:"defaultAccess,omitempty"` DefaultAccess string `json:"defaultAccess,omitempty" yaml:"defaultAccess,omitempty"`
StoreName string `json:"storeName" yaml:"storeName"` StoreName string `json:"storeName,omitempty" yaml:"storeName,omitempty"`
AllowedSecrets []string `json:"allowedSecrets,omitempty" yaml:"allowedSecrets,omitempty"` AllowedSecrets []string `json:"allowedSecrets,omitempty" yaml:"allowedSecrets,omitempty"`
DeniedSecrets []string `json:"deniedSecrets,omitempty" yaml:"deniedSecrets,omitempty"` DeniedSecrets []string `json:"deniedSecrets,omitempty" yaml:"deniedSecrets,omitempty"`
} }
type PipelineSpec struct { type PipelineSpec struct {
Handlers []HandlerSpec `json:"handlers" yaml:"handlers"` Handlers []HandlerSpec `json:"handlers,omitempty" yaml:"handlers,omitempty"`
} }
// APISpec describes the configuration for Dapr APIs. // APISpec describes the configuration for Dapr APIs.
@ -171,9 +172,9 @@ func (r APIAccessRules) GetRulesByProtocol(protocol APIAccessRuleProtocol) []API
} }
type HandlerSpec struct { type HandlerSpec struct {
Name string `json:"name" yaml:"name"` Name string `json:"name,omitempty" yaml:"name,omitempty"`
Type string `json:"type" yaml:"type"` Type string `json:"type,omitempty" yaml:"type,omitempty"`
Version string `json:"version" yaml:"version"` Version string `json:"version,omitempty" yaml:"version,omitempty"`
SelectorSpec SelectorSpec `json:"selector,omitempty" yaml:"selector,omitempty"` SelectorSpec SelectorSpec `json:"selector,omitempty" yaml:"selector,omitempty"`
} }
@ -183,7 +184,7 @@ func (h HandlerSpec) LogName() string {
} }
type SelectorSpec struct { type SelectorSpec struct {
Fields []SelectorField `json:"fields" yaml:"fields"` Fields []SelectorField `json:"fields,omitempty" yaml:"fields,omitempty"`
} }
type SelectorField struct { type SelectorField struct {
@ -192,75 +193,89 @@ type SelectorField struct {
} }
type TracingSpec struct { type TracingSpec struct {
SamplingRate string `json:"samplingRate" yaml:"samplingRate"` SamplingRate string `json:"samplingRate,omitempty" yaml:"samplingRate,omitempty"`
Stdout bool `json:"stdout" yaml:"stdout"` Stdout bool `json:"stdout,omitempty" yaml:"stdout,omitempty"`
Zipkin ZipkinSpec `json:"zipkin" yaml:"zipkin"` Zipkin *ZipkinSpec `json:"zipkin,omitempty" yaml:"zipkin,omitempty"`
Otel OtelSpec `json:"otel" yaml:"otel"` Otel *OtelSpec `json:"otel,omitempty" yaml:"otel,omitempty"`
} }
// ZipkinSpec defines Zipkin exporter configurations. // ZipkinSpec defines Zipkin exporter configurations.
type ZipkinSpec struct { type ZipkinSpec struct {
EndpointAddress string `json:"endpointAddress" yaml:"endpointAddress"` EndpointAddress string `json:"endpointAddress,omitempty" yaml:"endpointAddress,omitempty"`
} }
// OtelSpec defines Otel exporter configurations. // OtelSpec defines Otel exporter configurations.
type OtelSpec struct { type OtelSpec struct {
Protocol string `json:"protocol" yaml:"protocol"` Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"`
EndpointAddress string `json:"endpointAddress" yaml:"endpointAddress"` EndpointAddress string `json:"endpointAddress,omitempty" yaml:"endpointAddress,omitempty"`
IsSecure bool `json:"isSecure" yaml:"isSecure"` // Defaults to true
IsSecure *bool `json:"isSecure,omitempty" yaml:"isSecure,omitempty"`
}
// GetIsSecure returns true if the connection should be secured.
func (o OtelSpec) GetIsSecure() bool {
// Defaults to true if nil
return o.IsSecure == nil || *o.IsSecure
} }
// MetricSpec configuration for metrics. // MetricSpec configuration for metrics.
type MetricSpec struct { type MetricSpec struct {
Enabled bool `json:"enabled" yaml:"enabled"` // Defaults to true
Rules []MetricsRule `json:"rules" yaml:"rules"` Enabled *bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
Rules []MetricsRule `json:"rules,omitempty" yaml:"rules,omitempty"`
}
// GetEnabled returns true if metrics are enabled.
func (m MetricSpec) GetEnabled() bool {
// Defaults to true if nil
return m.Enabled == nil || *m.Enabled
} }
// MetricsRule defines configuration options for a metric. // MetricsRule defines configuration options for a metric.
type MetricsRule struct { type MetricsRule struct {
Name string `json:"name" yaml:"name"` Name string `json:"name,omitempty" yaml:"name,omitempty"`
Labels []MetricLabel `json:"labels" yaml:"labels"` Labels []MetricLabel `json:"labels,omitempty" yaml:"labels,omitempty"`
} }
// MetricsLabel defines an object that allows to set regex expressions for a label. // MetricsLabel defines an object that allows to set regex expressions for a label.
type MetricLabel struct { type MetricLabel struct {
Name string `json:"name" yaml:"name"` Name string `json:"name,omitempty" yaml:"name,omitempty"`
Regex map[string]string `json:"regex" yaml:"regex"` Regex map[string]string `json:"regex,omitempty" yaml:"regex,omitempty"`
} }
// AppPolicySpec defines the policy data structure for each app. // AppPolicySpec defines the policy data structure for each app.
type AppPolicySpec struct { type AppPolicySpec struct {
AppName string `json:"appId" yaml:"appId"` AppName string `json:"appId,omitempty" yaml:"appId,omitempty"`
DefaultAction string `json:"defaultAction" yaml:"defaultAction"` DefaultAction string `json:"defaultAction,omitempty" yaml:"defaultAction,omitempty"`
TrustDomain string `json:"trustDomain" yaml:"trustDomain"` TrustDomain string `json:"trustDomain,omitempty" yaml:"trustDomain,omitempty"`
Namespace string `json:"namespace" yaml:"namespace"` Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
AppOperationActions []AppOperation `json:"operations" yaml:"operations"` AppOperationActions []AppOperation `json:"operations,omitempty" yaml:"operations,omitempty"`
} }
// AppOperation defines the data structure for each app operation. // AppOperation defines the data structure for each app operation.
type AppOperation struct { type AppOperation struct {
Operation string `json:"name" yaml:"name"` Operation string `json:"name,omitempty" yaml:"name,omitempty"`
HTTPVerb []string `json:"httpVerb" yaml:"httpVerb"` HTTPVerb []string `json:"httpVerb,omitempty" yaml:"httpVerb,omitempty"`
Action string `json:"action" yaml:"action"` Action string `json:"action,omitempty" yaml:"action,omitempty"`
} }
// AccessControlSpec is the spec object in ConfigurationSpec. // AccessControlSpec is the spec object in ConfigurationSpec.
type AccessControlSpec struct { type AccessControlSpec struct {
DefaultAction string `json:"defaultAction" yaml:"defaultAction"` DefaultAction string `json:"defaultAction,omitempty" yaml:"defaultAction,omitempty"`
TrustDomain string `json:"trustDomain" yaml:"trustDomain"` TrustDomain string `json:"trustDomain,omitempty" yaml:"trustDomain,omitempty"`
AppPolicies []AppPolicySpec `json:"policies" yaml:"policies"` AppPolicies []AppPolicySpec `json:"policies,omitempty" yaml:"policies,omitempty"`
} }
type NameResolutionSpec struct { type NameResolutionSpec struct {
Component string `json:"component" yaml:"component"` Component string `json:"component,omitempty" yaml:"component,omitempty"`
Version string `json:"version" yaml:"version"` Version string `json:"version,omitempty" yaml:"version,omitempty"`
Configuration interface{} `json:"configuration" yaml:"configuration"` Configuration any `json:"configuration,omitempty" yaml:"configuration,omitempty"`
} }
type MTLSSpec struct { type MTLSSpec struct {
Enabled bool `json:"enabled" yaml:"enabled"` Enabled bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
WorkloadCertTTL string `json:"workloadCertTTL" yaml:"workloadCertTTL"` WorkloadCertTTL string `json:"workloadCertTTL,omitempty" yaml:"workloadCertTTL,omitempty"`
AllowedClockSkew string `json:"allowedClockSkew" yaml:"allowedClockSkew"` AllowedClockSkew string `json:"allowedClockSkew,omitempty" yaml:"allowedClockSkew,omitempty"`
} }
// SpiffeID represents the separated fields in a spiffe id. // SpiffeID represents the separated fields in a spiffe id.
@ -285,7 +300,7 @@ type ComponentsSpec struct {
// LoggingSpec defines the configuration for logging. // LoggingSpec defines the configuration for logging.
type LoggingSpec struct { type LoggingSpec struct {
// Configure API logging. // Configure API logging.
APILogging APILoggingSpec `json:"apiLogging,omitempty" yaml:"apiLogging,omitempty"` APILogging *APILoggingSpec `json:"apiLogging,omitempty" yaml:"apiLogging,omitempty"`
} }
// APILoggingSpec defines the configuration for API logging. // APILoggingSpec defines the configuration for API logging.
@ -296,7 +311,7 @@ type APILoggingSpec struct {
// When enabled, obfuscates the values of URLs in HTTP API logs, logging the route name rather than the full path being invoked, which could contain PII. // When enabled, obfuscates the values of URLs in HTTP API logs, logging the route name rather than the full path being invoked, which could contain PII.
// Default: false. // Default: false.
// This option has no effect if API logging is disabled. // This option has no effect if API logging is disabled.
ObfuscateURLs bool `json:"obfuscateURLs" yaml:"obfuscateURLs"` ObfuscateURLs bool `json:"obfuscateURLs,omitempty" yaml:"obfuscateURLs,omitempty"`
// If true, health checks are not reported in API logs. Default: false. // If true, health checks are not reported in API logs. Default: false.
// This option has no effect if API logging is disabled. // This option has no effect if API logging is disabled.
OmitHealthChecks bool `json:"omitHealthChecks,omitempty" yaml:"omitHealthChecks,omitempty"` OmitHealthChecks bool `json:"omitHealthChecks,omitempty" yaml:"omitHealthChecks,omitempty"`
@ -306,19 +321,15 @@ type APILoggingSpec struct {
func LoadDefaultConfiguration() *Configuration { func LoadDefaultConfiguration() *Configuration {
return &Configuration{ return &Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
TracingSpec: TracingSpec{ TracingSpec: &TracingSpec{
SamplingRate: "", Otel: &OtelSpec{
Otel: OtelSpec{ IsSecure: ptr.Of(true),
IsSecure: true,
}, },
}, },
MetricSpec: MetricSpec{ MetricSpec: &MetricSpec{
Enabled: true, Enabled: ptr.Of(true),
}, },
MetricsSpec: MetricSpec{ AccessControlSpec: &AccessControlSpec{
Enabled: true,
},
AccessControlSpec: AccessControlSpec{
DefaultAction: AllowAccess, DefaultAction: AllowAccess,
TrustDomain: "public", TrustDomain: "public",
}, },
@ -327,36 +338,41 @@ func LoadDefaultConfiguration() *Configuration {
} }
// LoadStandaloneConfiguration gets the path to a config file and loads it into a configuration. // LoadStandaloneConfiguration gets the path to a config file and loads it into a configuration.
func LoadStandaloneConfiguration(config string) (*Configuration, string, error) { func LoadStandaloneConfiguration(configs ...string) (*Configuration, error) {
_, err := os.Stat(config)
if err != nil {
return nil, "", err
}
b, err := os.ReadFile(config)
if err != nil {
return nil, "", err
}
// Parse environment variables from yaml
b = []byte(os.ExpandEnv(string(b)))
conf := LoadDefaultConfiguration() conf := LoadDefaultConfiguration()
err = yaml.Unmarshal(b, conf)
if err != nil { // Load all config files and apply them on top of the default config
return nil, string(b), err for _, config := range configs {
} _, err := os.Stat(config)
err = sortAndValidateSecretsConfiguration(conf) if err != nil {
if err != nil { return nil, err
return nil, string(b), err }
b, err := os.ReadFile(config)
if err != nil {
return nil, err
}
// Parse environment variables from yaml
b = []byte(os.ExpandEnv(string(b)))
err = yaml.Unmarshal(b, conf)
if err != nil {
return nil, err
}
} }
sortMetricsSpec(conf) err := conf.sortAndValidateSecretsConfiguration()
return conf, string(b), nil if err != nil {
return nil, err
}
conf.sortMetricsSpec()
return conf, nil
} }
// LoadKubernetesConfiguration gets configuration from the Kubernetes operator with a given name. // LoadKubernetesConfiguration gets configuration from the Kubernetes operator with a given name.
func LoadKubernetesConfiguration(config, namespace string, podName string, operatorClient operatorv1pb.OperatorClient) (*Configuration, error) { func LoadKubernetesConfiguration(config string, namespace string, podName string, operatorClient operatorv1pb.OperatorClient) (*Configuration, error) {
resp, err := operatorClient.GetConfiguration(context.Background(), &operatorv1pb.GetConfigurationRequest{ resp, err := operatorClient.GetConfiguration(context.Background(), &operatorv1pb.GetConfigurationRequest{
Name: config, Name: config,
Namespace: namespace, Namespace: namespace,
@ -365,21 +381,22 @@ func LoadKubernetesConfiguration(config, namespace string, podName string, opera
if err != nil { if err != nil {
return nil, err return nil, err
} }
if resp.GetConfiguration() == nil { b := resp.GetConfiguration()
if len(b) == 0 {
return nil, fmt.Errorf("configuration %s not found", config) return nil, fmt.Errorf("configuration %s not found", config)
} }
conf := LoadDefaultConfiguration() conf := LoadDefaultConfiguration()
err = json.Unmarshal(resp.GetConfiguration(), conf) err = json.Unmarshal(b, conf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = sortAndValidateSecretsConfiguration(conf) err = conf.sortAndValidateSecretsConfiguration()
if err != nil { if err != nil {
return nil, err return nil, err
} }
sortMetricsSpec(conf) conf.sortMetricsSpec()
return conf, nil return conf, nil
} }
@ -410,46 +427,11 @@ func SetTracingSpecFromEnv(conf *Configuration) {
} }
if insecure := os.Getenv(env.OtlpExporterInsecure); insecure == "true" { if insecure := os.Getenv(env.OtlpExporterInsecure); insecure == "true" {
conf.Spec.TracingSpec.Otel.IsSecure = false conf.Spec.TracingSpec.Otel.IsSecure = ptr.Of(false)
} }
} }
} }
// Apply .metrics if set. If not, retain .metric.
func sortMetricsSpec(conf *Configuration) {
if !conf.Spec.MetricsSpec.Enabled {
conf.Spec.MetricSpec.Enabled = false
}
if len(conf.Spec.MetricsSpec.Rules) > 0 {
conf.Spec.MetricSpec.Rules = conf.Spec.MetricsSpec.Rules
}
}
// Validate the secrets configuration and sort to the allowed and denied lists if present.
func sortAndValidateSecretsConfiguration(conf *Configuration) error {
scopes := conf.Spec.Secrets.Scopes
set := sets.NewString()
for _, scope := range scopes {
// validate scope
if set.Has(scope.StoreName) {
return fmt.Errorf("%q storeName is repeated in secrets configuration", scope.StoreName)
}
if scope.DefaultAccess != "" &&
!strings.EqualFold(scope.DefaultAccess, AllowAccess) &&
!strings.EqualFold(scope.DefaultAccess, DenyAccess) {
return fmt.Errorf("defaultAccess %q can be either allow or deny", scope.DefaultAccess)
}
set.Insert(scope.StoreName)
// modify scope
sort.Strings(scope.AllowedSecrets)
sort.Strings(scope.DeniedSecrets)
}
return nil
}
// IsSecretAllowed Check if the secret is allowed to be accessed. // IsSecretAllowed Check if the secret is allowed to be accessed.
func (c SecretsScope) IsSecretAllowed(key string) bool { func (c SecretsScope) IsSecretAllowed(key string) bool {
// By default, set allow access for the secret store. // By default, set allow access for the secret store.
@ -515,3 +497,133 @@ func (c Configuration) EnabledFeatures() []string {
} }
return features[:i] return features[:i]
} }
// GetTracingSpec returns the tracing spec.
// It's a short-hand that includes nil-checks for safety.
func (c Configuration) GetTracingSpec() TracingSpec {
if c.Spec.TracingSpec == nil {
return TracingSpec{}
}
return *c.Spec.TracingSpec
}
// GetMTLSSpec returns the mTLS spec.
// It's a short-hand that includes nil-checks for safety.
func (c Configuration) GetMTLSSpec() MTLSSpec {
if c.Spec.MTLSSpec == nil {
return MTLSSpec{}
}
return *c.Spec.MTLSSpec
}
// GetMetricsSpec returns the metrics spec.
// It's a short-hand that includes nil-checks for safety.
func (c Configuration) GetMetricsSpec() MetricSpec {
if c.Spec.MetricSpec == nil {
return MetricSpec{}
}
return *c.Spec.MetricSpec
}
// GetAPISpec returns the API spec.
// It's a short-hand that includes nil-checks for safety.
func (c Configuration) GetAPISpec() APISpec {
if c.Spec.APISpec == nil {
return APISpec{}
}
return *c.Spec.APISpec
}
// GetLoggingSpec returns the Logging spec.
// It's a short-hand that includes nil-checks for safety.
func (c Configuration) GetLoggingSpec() LoggingSpec {
if c.Spec.LoggingSpec == nil {
return LoggingSpec{}
}
return *c.Spec.LoggingSpec
}
// GetLoggingSpec returns the Logging.APILogging spec.
// It's a short-hand that includes nil-checks for safety.
func (c Configuration) GetAPILoggingSpec() APILoggingSpec {
if c.Spec.LoggingSpec == nil || c.Spec.LoggingSpec.APILogging == nil {
return APILoggingSpec{}
}
return *c.Spec.LoggingSpec.APILogging
}
// ToYAML returns the Configuration represented as YAML.
func (c *Configuration) ToYAML() (string, error) {
b, err := yaml.Marshal(c)
if err != nil {
return "", err
}
return string(b), nil
}
// String implements fmt.Stringer and is used for debugging. It returns the Configuration object encoded as YAML.
func (c *Configuration) String() string {
enc, err := c.ToYAML()
if err != nil {
return "Failed to marshal Configuration object to YAML: " + err.Error()
}
return enc
}
// Apply .metrics if set. If not, retain .metric.
func (c *Configuration) sortMetricsSpec() {
if c.Spec.MetricsSpec != nil {
if c.Spec.MetricsSpec.Enabled != nil {
c.Spec.MetricSpec.Enabled = c.Spec.MetricsSpec.Enabled
}
if len(c.Spec.MetricsSpec.Rules) > 0 {
c.Spec.MetricSpec.Rules = c.Spec.MetricsSpec.Rules
}
}
}
// Validate the secrets configuration and sort to the allowed and denied lists if present.
func (c *Configuration) sortAndValidateSecretsConfiguration() error {
if c.Spec.Secrets == nil {
return nil
}
set := sets.NewString()
for _, scope := range c.Spec.Secrets.Scopes {
// validate scope
if set.Has(scope.StoreName) {
return fmt.Errorf("%s storeName is repeated in secrets configuration", scope.StoreName)
}
if scope.DefaultAccess != "" &&
!strings.EqualFold(scope.DefaultAccess, AllowAccess) &&
!strings.EqualFold(scope.DefaultAccess, DenyAccess) {
return fmt.Errorf("defaultAccess %s can be either allow or deny", scope.DefaultAccess)
}
set.Insert(scope.StoreName)
// modify scope
sort.Strings(scope.AllowedSecrets)
sort.Strings(scope.DeniedSecrets)
}
return nil
}
// ToYAML returns the ConfigurationSpec represented as YAML.
func (c ConfigurationSpec) ToYAML() (string, error) {
b, err := yaml.Marshal(&c)
if err != nil {
return "", err
}
return string(b), nil
}
// String implements fmt.Stringer and is used for debugging. It returns the Configuration object encoded as YAML.
func (c ConfigurationSpec) String() string {
enc, err := c.ToYAML()
if err != nil {
return fmt.Sprintf("Failed to marshal ConfigurationSpec object to YAML: %v", err)
}
return enc
}

View File

@ -14,12 +14,17 @@ limitations under the License.
package config package config
import ( import (
"bytes"
"os"
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/dapr/dapr/pkg/buildinfo"
"github.com/dapr/kit/ptr"
) )
func TestLoadStandaloneConfiguration(t *testing.T) { func TestLoadStandaloneConfiguration(t *testing.T) {
@ -47,7 +52,7 @@ func TestLoadStandaloneConfiguration(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
config, _, err := LoadStandaloneConfiguration(tc.path) config, err := LoadStandaloneConfiguration(tc.path)
if tc.errorExpected { if tc.errorExpected {
assert.Error(t, err, "Expected an error") assert.Error(t, err, "Expected an error")
assert.Nil(t, config, "Config should not be loaded") assert.Nil(t, config, "Config should not be loaded")
@ -58,72 +63,165 @@ func TestLoadStandaloneConfiguration(t *testing.T) {
}) })
} }
t.Run("Parse environment variables", func(t *testing.T) { t.Run("parse environment variables", func(t *testing.T) {
t.Setenv("DAPR_SECRET", "keepitsecret") t.Setenv("DAPR_SECRET", "keepitsecret")
config, _, err := LoadStandaloneConfiguration("./testdata/env_variables_config.yaml") config, err := LoadStandaloneConfiguration("./testdata/env_variables_config.yaml")
assert.NoError(t, err, "Unexpected error") assert.NoError(t, err, "Unexpected error")
assert.NotNil(t, config, "Config not loaded as expected") assert.NotNil(t, config, "Config not loaded as expected")
assert.Equal(t, "keepitsecret", config.Spec.Secrets.Scopes[0].AllowedSecrets[0]) assert.Equal(t, "keepitsecret", config.Spec.Secrets.Scopes[0].AllowedSecrets[0])
}) })
}
func TestLoadStandaloneConfigurationKindName(t *testing.T) { t.Run("check Kind and Name", func(t *testing.T) {
t.Run("test Kind and Name", func(t *testing.T) { config, err := LoadStandaloneConfiguration("./testdata/config.yaml")
config, _, err := LoadStandaloneConfiguration("./testdata/config.yaml")
assert.NoError(t, err, "Unexpected error") assert.NoError(t, err, "Unexpected error")
assert.NotNil(t, config, "Config not loaded as expected") assert.NotNil(t, config, "Config not loaded as expected")
assert.Equal(t, "secretappconfig", config.ObjectMeta.Name) assert.Equal(t, "secretappconfig", config.ObjectMeta.Name)
assert.Equal(t, "Configuration", config.TypeMeta.Kind) assert.Equal(t, "Configuration", config.TypeMeta.Kind)
}) })
t.Run("metrics spec", func(t *testing.T) {
testCases := []struct {
name string
confFile string
metricEnabled bool
}{
{
name: "metric is enabled by default",
confFile: "./testdata/config.yaml",
metricEnabled: true,
},
{
name: "metric is disabled by config",
confFile: "./testdata/metric_disabled.yaml",
metricEnabled: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config, err := LoadStandaloneConfiguration(tc.confFile)
assert.NoError(t, err)
assert.Equal(t, tc.metricEnabled, config.Spec.MetricSpec.GetEnabled())
})
}
})
t.Run("components spec", func(t *testing.T) {
testCases := []struct {
name string
confFile string
componentsDeny []string
}{
{
name: "component deny list",
confFile: "./testdata/components_config.yaml",
componentsDeny: []string{"foo.bar", "hello.world/v1"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config, err := LoadStandaloneConfiguration(tc.confFile)
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(tc.componentsDeny, config.Spec.ComponentsSpec.Deny))
})
}
})
t.Run("features spec", func(t *testing.T) {
testCases := []struct {
name string
confFile string
featureName Feature
featureEnabled bool
}{
{
name: "feature is enabled",
confFile: "./testdata/feature_config.yaml",
featureName: Feature("Actor.Reentrancy"),
featureEnabled: true,
},
{
name: "feature is disabled",
confFile: "./testdata/feature_config.yaml",
featureName: Feature("Test.Feature"),
featureEnabled: false,
},
{
name: "feature is disabled if missing",
confFile: "./testdata/feature_config.yaml",
featureName: Feature("Test.Missing"),
featureEnabled: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config, err := LoadStandaloneConfiguration(tc.confFile)
require.NoError(t, err)
config.LoadFeatures()
assert.Equal(t, tc.featureEnabled, config.IsFeatureEnabled(tc.featureName))
})
}
})
t.Run("mTLS spec", func(t *testing.T) {
config, err := LoadStandaloneConfiguration("./testdata/mtls_config.yaml")
require.NoError(t, err)
mtlsSpec := config.GetMTLSSpec()
assert.True(t, mtlsSpec.Enabled)
assert.Equal(t, "25s", mtlsSpec.WorkloadCertTTL)
assert.Equal(t, "1h", mtlsSpec.AllowedClockSkew)
})
t.Run("multiple configurations", func(t *testing.T) {
config, err := LoadStandaloneConfiguration("./testdata/feature_config.yaml", "./testdata/mtls_config.yaml")
require.NoError(t, err)
// From feature_config.yaml
config.LoadFeatures()
assert.True(t, config.IsFeatureEnabled("Actor.Reentrancy"))
assert.False(t, config.IsFeatureEnabled("Test.Feature"))
// From mtls_config.yaml
mtlsSpec := config.GetMTLSSpec()
assert.True(t, mtlsSpec.Enabled)
assert.Equal(t, "25s", mtlsSpec.WorkloadCertTTL)
assert.Equal(t, "1h", mtlsSpec.AllowedClockSkew)
})
t.Run("multiple configurations with overriding", func(t *testing.T) {
config, err := LoadStandaloneConfiguration("./testdata/feature_config.yaml", "./testdata/mtls_config.yaml", "./testdata/override.yaml")
require.NoError(t, err)
// From feature_config.yaml
// Should both be overridden
config.LoadFeatures()
assert.False(t, config.IsFeatureEnabled("Actor.Reentrancy"))
assert.True(t, config.IsFeatureEnabled("Test.Feature"))
// From mtls_config.yaml
mtlsSpec := config.GetMTLSSpec()
assert.False(t, mtlsSpec.Enabled) // Overridden
assert.Equal(t, "25s", mtlsSpec.WorkloadCertTTL)
assert.Equal(t, "1h", mtlsSpec.AllowedClockSkew)
// Spec part encoded as YAML
compareWithFile(t, "./testdata/override_spec_gen.yaml", config.Spec.String())
// Complete YAML
compareWithFile(t, "./testdata/override_gen.yaml", config.String())
})
} }
func TestMetricSpecForStandAlone(t *testing.T) { func compareWithFile(t *testing.T, file string, expect string) {
testCases := []struct { f, err := os.ReadFile(file)
name string require.NoError(t, err)
confFile string
metricEnabled bool
}{
{
name: "metric is enabled by default",
confFile: "./testdata/config.yaml",
metricEnabled: true,
},
{
name: "metric is disabled by config",
confFile: "./testdata/metric_disabled.yaml",
metricEnabled: false,
},
}
for _, tc := range testCases { // Replace all "\r\n" with "\n" because (*wave hands*, *lesigh*) ... Windows
t.Run(tc.name, func(t *testing.T) { f = bytes.ReplaceAll(f, []byte{'\r', '\n'}, []byte{'\n'})
config, _, err := LoadStandaloneConfiguration(tc.confFile)
assert.NoError(t, err)
assert.Equal(t, tc.metricEnabled, config.Spec.MetricSpec.Enabled)
})
}
}
func TestComponentsSpecForStandAlone(t *testing.T) { assert.Equal(t, expect, string(f))
testCases := []struct {
name string
confFile string
componentsDeny []string
}{
{
name: "component deny list",
confFile: "./testdata/components_config.yaml",
componentsDeny: []string{"foo.bar", "hello.world/v1"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config, _, err := LoadStandaloneConfiguration(tc.confFile)
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(tc.componentsDeny, config.Spec.ComponentsSpec.Deny))
})
}
} }
func TestSortAndValidateSecretsConfigration(t *testing.T) { func TestSortAndValidateSecretsConfigration(t *testing.T) {
@ -140,7 +238,7 @@ func TestSortAndValidateSecretsConfigration(t *testing.T) {
name: "incorrect default access", name: "incorrect default access",
config: Configuration{ config: Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
Secrets: SecretsSpec{ Secrets: &SecretsSpec{
Scopes: []SecretsScope{ Scopes: []SecretsScope{
{ {
StoreName: "testStore", StoreName: "testStore",
@ -156,7 +254,7 @@ func TestSortAndValidateSecretsConfigration(t *testing.T) {
name: "empty default access", name: "empty default access",
config: Configuration{ config: Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
Secrets: SecretsSpec{ Secrets: &SecretsSpec{
Scopes: []SecretsScope{ Scopes: []SecretsScope{
{ {
StoreName: "testStore", StoreName: "testStore",
@ -171,7 +269,7 @@ func TestSortAndValidateSecretsConfigration(t *testing.T) {
name: "repeated store Name", name: "repeated store Name",
config: Configuration{ config: Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
Secrets: SecretsSpec{ Secrets: &SecretsSpec{
Scopes: []SecretsScope{ Scopes: []SecretsScope{
{ {
StoreName: "testStore", StoreName: "testStore",
@ -191,7 +289,7 @@ func TestSortAndValidateSecretsConfigration(t *testing.T) {
name: "simple secrets config", name: "simple secrets config",
config: Configuration{ config: Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
Secrets: SecretsSpec{ Secrets: &SecretsSpec{
Scopes: []SecretsScope{ Scopes: []SecretsScope{
{ {
StoreName: "testStore", StoreName: "testStore",
@ -208,7 +306,7 @@ func TestSortAndValidateSecretsConfigration(t *testing.T) {
name: "case-insensitive default access", name: "case-insensitive default access",
config: Configuration{ config: Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
Secrets: SecretsSpec{ Secrets: &SecretsSpec{
Scopes: []SecretsScope{ Scopes: []SecretsScope{
{ {
StoreName: "testStore", StoreName: "testStore",
@ -224,10 +322,10 @@ func TestSortAndValidateSecretsConfigration(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
err := sortAndValidateSecretsConfiguration(&tc.config) err := tc.config.sortAndValidateSecretsConfiguration()
if tc.errorExpected { if tc.errorExpected {
assert.Error(t, err, "expected validation to fail") assert.Error(t, err, "expected validation to fail")
} else { } else if tc.config.Spec.Secrets != nil {
for _, scope := range tc.config.Spec.Secrets.Scopes { for _, scope := range tc.config.Spec.Secrets.Scopes {
assert.True(t, sort.StringsAreSorted(scope.AllowedSecrets), "expected sorted slice") assert.True(t, sort.StringsAreSorted(scope.AllowedSecrets), "expected sorted slice")
assert.True(t, sort.StringsAreSorted(scope.DeniedSecrets), "expected sorted slice") assert.True(t, sort.StringsAreSorted(scope.DeniedSecrets), "expected sorted slice")
@ -340,56 +438,18 @@ func TestFeatureEnabled(t *testing.T) {
}, },
} }
config.LoadFeatures() config.LoadFeatures()
assert.True(t, config.IsFeatureEnabled("testEnabled")) assert.True(t, config.IsFeatureEnabled("testEnabled"))
assert.False(t, config.IsFeatureEnabled("testDisabled")) assert.False(t, config.IsFeatureEnabled("testDisabled"))
assert.False(t, config.IsFeatureEnabled("testMissing")) assert.False(t, config.IsFeatureEnabled("testMissing"))
}
func TestFeatureSpecForStandAlone(t *testing.T) { // Test config.EnabledFeatures
testCases := []struct { // We sort the values before comparing because order isn't guaranteed (and doesn't matter)
name string actual := config.EnabledFeatures()
confFile string expect := append([]string{"testEnabled"}, buildinfo.Features()...)
featureName Feature sort.Strings(actual)
featureEnabled bool sort.Strings(expect)
}{ assert.EqualValues(t, actual, expect)
{
name: "Feature is enabled",
confFile: "./testdata/feature_config.yaml",
featureName: Feature("Actor.Reentrancy"),
featureEnabled: true,
},
{
name: "Feature is disabled",
confFile: "./testdata/feature_config.yaml",
featureName: Feature("Test.Feature"),
featureEnabled: false,
},
{
name: "Feature is disabled if missing",
confFile: "./testdata/feature_config.yaml",
featureName: Feature("Test.Missing"),
featureEnabled: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config, _, err := LoadStandaloneConfiguration(tc.confFile)
require.NoError(t, err)
config.LoadFeatures()
assert.Equal(t, tc.featureEnabled, config.IsFeatureEnabled(tc.featureName))
})
}
}
func TestMTLSSpecForStandAlone(t *testing.T) {
t.Run("test mtls spec config", func(t *testing.T) {
config, _, err := LoadStandaloneConfiguration("./testdata/mtls_config.yaml")
require.NoError(t, err)
assert.True(t, config.Spec.MTLSSpec.Enabled)
assert.Equal(t, "25s", config.Spec.MTLSSpec.WorkloadCertTTL)
assert.Equal(t, "1h", config.Spec.MTLSSpec.AllowedClockSkew)
})
} }
func TestSetTracingSpecFromEnv(t *testing.T) { func TestSetTracingSpecFromEnv(t *testing.T) {
@ -405,42 +465,84 @@ func TestSetTracingSpecFromEnv(t *testing.T) {
assert.Equal(t, "otlpendpoint:1234", conf.Spec.TracingSpec.Otel.EndpointAddress) assert.Equal(t, "otlpendpoint:1234", conf.Spec.TracingSpec.Otel.EndpointAddress)
assert.Equal(t, "http", conf.Spec.TracingSpec.Otel.Protocol) assert.Equal(t, "http", conf.Spec.TracingSpec.Otel.Protocol)
assert.Equal(t, false, conf.Spec.TracingSpec.Otel.IsSecure) require.False(t, conf.Spec.TracingSpec.Otel.GetIsSecure())
// Spec from config file should not be overridden // Spec from config file should not be overridden
conf = LoadDefaultConfiguration() conf = LoadDefaultConfiguration()
conf.Spec.TracingSpec.Otel.EndpointAddress = "configfileendpoint:4321" conf.Spec.TracingSpec.Otel.EndpointAddress = "configfileendpoint:4321"
conf.Spec.TracingSpec.Otel.Protocol = "grpc" conf.Spec.TracingSpec.Otel.Protocol = "grpc"
conf.Spec.TracingSpec.Otel.IsSecure = true conf.Spec.TracingSpec.Otel.IsSecure = ptr.Of(true)
// set tracing spec from env // set tracing spec from env
SetTracingSpecFromEnv(conf) SetTracingSpecFromEnv(conf)
assert.Equal(t, "configfileendpoint:4321", conf.Spec.TracingSpec.Otel.EndpointAddress) assert.Equal(t, "configfileendpoint:4321", conf.Spec.TracingSpec.Otel.EndpointAddress)
assert.Equal(t, "grpc", conf.Spec.TracingSpec.Otel.Protocol) assert.Equal(t, "grpc", conf.Spec.TracingSpec.Otel.Protocol)
assert.Equal(t, true, conf.Spec.TracingSpec.Otel.IsSecure) require.True(t, conf.Spec.TracingSpec.Otel.GetIsSecure())
} }
func TestSortMetrics(t *testing.T) { func TestSortMetrics(t *testing.T) {
t.Run("metrics overrides metric", func(t *testing.T) { t.Run("metrics overrides metric - enabled false", func(t *testing.T) {
config := &Configuration{ config := &Configuration{
Spec: ConfigurationSpec{ Spec: ConfigurationSpec{
MetricSpec: MetricSpec{ MetricSpec: &MetricSpec{
Enabled: true, Enabled: ptr.Of(true),
Rules: []MetricsRule{ Rules: []MetricsRule{
{ {
Name: "rule", Name: "rule",
}, },
}, },
}, },
MetricsSpec: MetricSpec{ MetricsSpec: &MetricSpec{
Enabled: false, Enabled: ptr.Of(false),
}, },
}, },
} }
sortMetricsSpec(config) config.sortMetricsSpec()
assert.False(t, config.Spec.MetricSpec.Enabled) assert.False(t, config.Spec.MetricSpec.GetEnabled())
assert.Equal(t, "rule", config.Spec.MetricSpec.Rules[0].Name)
})
t.Run("metrics overrides metric - enabled true", func(t *testing.T) {
config := &Configuration{
Spec: ConfigurationSpec{
MetricSpec: &MetricSpec{
Enabled: ptr.Of(false),
Rules: []MetricsRule{
{
Name: "rule",
},
},
},
MetricsSpec: &MetricSpec{
Enabled: ptr.Of(true),
},
},
}
config.sortMetricsSpec()
assert.True(t, config.Spec.MetricSpec.GetEnabled())
assert.Equal(t, "rule", config.Spec.MetricSpec.Rules[0].Name)
})
t.Run("nil metrics enabled doesn't overrides", func(t *testing.T) {
config := &Configuration{
Spec: ConfigurationSpec{
MetricSpec: &MetricSpec{
Enabled: ptr.Of(true),
Rules: []MetricsRule{
{
Name: "rule",
},
},
},
MetricsSpec: &MetricSpec{},
},
}
config.sortMetricsSpec()
assert.True(t, config.Spec.MetricSpec.GetEnabled())
assert.Equal(t, "rule", config.Spec.MetricSpec.Rules[0].Name) assert.Equal(t, "rule", config.Spec.MetricSpec.Rules[0].Name)
}) })
} }

View File

@ -5,6 +5,6 @@ metadata:
spec: spec:
secrets: secrets:
scopes: scopes:
- storeName: "local" - storeName: "local"
defaultAccess: "allow" defaultAccess: "allow"
allowedSecrets: ["daprsecret","redissecret"] allowedSecrets: ["daprsecret","redissecret"]

View File

@ -5,6 +5,6 @@ metadata:
spec: spec:
secrets: secrets:
scopes: scopes:
- storeName: "local" - storeName: "local"
defaultAccess: "allow" defaultAccess: "allow"
allowedSecrets: ["${DAPR_SECRET}"] allowedSecrets: ["${DAPR_SECRET}"]

View File

@ -4,7 +4,7 @@ metadata:
name: daprConfig name: daprConfig
spec: spec:
features: features:
- name: Actor.Reentrancy - name: Actor.Reentrancy
enabled: true enabled: true
- name: Test.Feature - name: Test.Feature
enabled: false enabled: false

View File

@ -5,7 +5,7 @@ metadata:
spec: spec:
secrets: secrets:
scopes: scopes:
- storeName: "local" - storeName: "local"
defaultAccess: "allow" defaultAccess: "allow"
- storeName: "local" - storeName: "local"
defaultAccess: "deny" defaultAccess: "deny"

11
pkg/config/testdata/override.yaml vendored Normal file
View File

@ -0,0 +1,11 @@
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprsystem
namespace: default
spec:
mtls:
enabled: false
features:
- name: Test.Feature
enabled: true

33
pkg/config/testdata/override_gen.yaml vendored Normal file
View File

@ -0,0 +1,33 @@
kind: Configuration
apiversion: ""
metadata:
name: daprsystem
generatename: ""
namespace: default
selflink: ""
uid: ""
resourceversion: ""
generation: 0
creationtimestamp: "0001-01-01T00:00:00Z"
deletiontimestamp: null
deletiongraceperiodseconds: null
labels: {}
annotations: {}
ownerreferences: []
finalizers: []
managedfields: []
spec:
tracing:
otel:
isSecure: true
mtls:
workloadCertTTL: 25s
allowedClockSkew: 1h
metric:
enabled: true
accessControl:
defaultAction: allow
trustDomain: public
features:
- name: Test.Feature
enabled: true

View File

@ -0,0 +1,14 @@
tracing:
otel:
isSecure: true
mtls:
workloadCertTTL: 25s
allowedClockSkew: 1h
metric:
enabled: true
accessControl:
defaultAction: allow
trustDomain: public
features:
- name: Test.Feature
enabled: true

View File

@ -215,9 +215,8 @@ func ConstructSubscriptionSpanAttributes(topic string) map[string]string {
} }
// StartInternalCallbackSpan starts trace span for internal callback such as input bindings and pubsub subscription. // StartInternalCallbackSpan starts trace span for internal callback such as input bindings and pubsub subscription.
func StartInternalCallbackSpan(ctx context.Context, spanName string, parent trace.SpanContext, spec config.TracingSpec) (context.Context, trace.Span) { func StartInternalCallbackSpan(ctx context.Context, spanName string, parent trace.SpanContext, spec *config.TracingSpec) (context.Context, trace.Span) {
traceEnabled := diagUtils.IsTracingEnabled(spec.SamplingRate) if spec == nil || !diagUtils.IsTracingEnabled(spec.SamplingRate) {
if !traceEnabled {
return ctx, nil return ctx, nil
} }

View File

@ -122,7 +122,7 @@ func TestStartInternalCallbackSpan(t *testing.T) {
otel.SetTracerProvider(tp) otel.SetTracerProvider(tp)
t.Run("traceparent is provided and sampling is enabled", func(t *testing.T) { t.Run("traceparent is provided and sampling is enabled", func(t *testing.T) {
traceSpec := config.TracingSpec{SamplingRate: "1"} traceSpec := &config.TracingSpec{SamplingRate: "1"}
scConfig := trace.SpanContextConfig{ scConfig := trace.SpanContextConfig{
TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54}, TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
@ -142,7 +142,7 @@ func TestStartInternalCallbackSpan(t *testing.T) {
}) })
t.Run("traceparent is provided with sampling flag = 1 but sampling is disabled", func(t *testing.T) { t.Run("traceparent is provided with sampling flag = 1 but sampling is disabled", func(t *testing.T) {
traceSpec := config.TracingSpec{SamplingRate: "0"} traceSpec := &config.TracingSpec{SamplingRate: "0"}
scConfig := trace.SpanContextConfig{ scConfig := trace.SpanContextConfig{
TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54}, TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},

View File

@ -238,7 +238,7 @@ func (s *server) getMiddlewareOptions() []grpcGo.ServerOption {
intrStream = append(intrStream, diag.GRPCTraceStreamServerInterceptor(s.config.AppID, s.tracingSpec)) intrStream = append(intrStream, diag.GRPCTraceStreamServerInterceptor(s.config.AppID, s.tracingSpec))
} }
if s.metricSpec.Enabled { if s.metricSpec.GetEnabled() {
s.logger.Info("Enabled gRPC metrics middleware") s.logger.Info("Enabled gRPC metrics middleware")
intr = append(intr, diag.DefaultGRPCMonitoring.UnaryServerInterceptor()) intr = append(intr, diag.DefaultGRPCMonitoring.UnaryServerInterceptor())

View File

@ -243,7 +243,7 @@ func (s *server) useTracing(r chi.Router) {
} }
func (s *server) useMetrics(r chi.Router) { func (s *server) useMetrics(r chi.Router) {
if !s.metricSpec.Enabled { if !s.metricSpec.GetEnabled() {
return return
} }

View File

@ -23,7 +23,7 @@ import (
"github.com/dapr/dapr/utils" "github.com/dapr/dapr/utils"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v3"
) )
const ( const (

View File

@ -172,7 +172,7 @@ func mTLSEnabled(daprClient scheme.Interface) bool {
for _, c := range resp.Items { for _, c := range resp.Items {
if c.GetName() == defaultConfig { if c.GetName() == defaultConfig {
return c.Spec.MTLSSpec.Enabled return c.Spec.MTLSSpec.GetEnabled()
} }
} }
log.Infof("Dapr system configuration (%s) is not found, use default value %t for mTLSEnabled", defaultConfig, defaultMtlsEnabled) log.Infof("Dapr system configuration (%s) is not found, use default value %t for mTLSEnabled", defaultConfig, defaultMtlsEnabled)

View File

@ -138,7 +138,6 @@ func GetSidecarContainer(cfg ContainerConfig) (*corev1.Container, error) {
"--control-plane-address", cfg.ControlPlaneAddress, "--control-plane-address", cfg.ControlPlaneAddress,
"--app-protocol", cfg.Annotations.GetStringOrDefault(annotations.KeyAppProtocol, annotations.DefaultAppProtocol), "--app-protocol", cfg.Annotations.GetStringOrDefault(annotations.KeyAppProtocol, annotations.DefaultAppProtocol),
"--placement-host-address", cfg.PlacementServiceAddress, "--placement-host-address", cfg.PlacementServiceAddress,
"--config", cfg.Annotations.GetString(annotations.KeyConfig),
"--log-level", cfg.Annotations.GetStringOrDefault(annotations.KeyLogLevel, annotations.DefaultLogLevel), "--log-level", cfg.Annotations.GetStringOrDefault(annotations.KeyLogLevel, annotations.DefaultLogLevel),
"--app-max-concurrency", strconv.Itoa(int(maxConcurrency)), "--app-max-concurrency", strconv.Itoa(int(maxConcurrency)),
"--sentry-address", cfg.SentryAddress, "--sentry-address", cfg.SentryAddress,
@ -150,6 +149,10 @@ func GetSidecarContainer(cfg ContainerConfig) (*corev1.Container, error) {
"--disable-builtin-k8s-secret-store=" + strconv.FormatBool(disableBuiltinK8sSecretStore), "--disable-builtin-k8s-secret-store=" + strconv.FormatBool(disableBuiltinK8sSecretStore),
} }
if v := cfg.Annotations.GetString(annotations.KeyConfig); v != "" {
args = append(args, "--config", v)
}
if v, ok := cfg.Annotations[annotations.KeyAppChannel]; ok && v != "" { if v, ok := cfg.Annotations[annotations.KeyAppChannel]; ok && v != "" {
args = append(args, "--app-channel-address", v) args = append(args, "--app-channel-address", v)
} }

View File

@ -18,6 +18,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
@ -34,14 +35,14 @@ const (
func TestGetResourceRequirements(t *testing.T) { func TestGetResourceRequirements(t *testing.T) {
t.Run("no resource requirements", func(t *testing.T) { t.Run("no resource requirements", func(t *testing.T) {
r, err := getResourceRequirements(nil) r, err := getResourceRequirements(nil)
assert.Nil(t, err) require.NoError(t, err)
assert.Nil(t, r) assert.Nil(t, r)
}) })
t.Run("valid resource limits", func(t *testing.T) { t.Run("valid resource limits", func(t *testing.T) {
a := map[string]string{annotations.KeyCPULimit: "100m", annotations.KeyMemoryLimit: "1Gi"} a := map[string]string{annotations.KeyCPULimit: "100m", annotations.KeyMemoryLimit: "1Gi"}
r, err := getResourceRequirements(a) r, err := getResourceRequirements(a)
assert.Nil(t, err) require.NoError(t, err)
assert.Equal(t, "100m", r.Limits.Cpu().String()) assert.Equal(t, "100m", r.Limits.Cpu().String())
assert.Equal(t, "1Gi", r.Limits.Memory().String()) assert.Equal(t, "1Gi", r.Limits.Memory().String())
}) })
@ -63,7 +64,7 @@ func TestGetResourceRequirements(t *testing.T) {
t.Run("valid resource requests", func(t *testing.T) { t.Run("valid resource requests", func(t *testing.T) {
a := map[string]string{annotations.KeyCPURequest: "100m", annotations.KeyMemoryRequest: "1Gi"} a := map[string]string{annotations.KeyCPURequest: "100m", annotations.KeyMemoryRequest: "1Gi"}
r, err := getResourceRequirements(a) r, err := getResourceRequirements(a)
assert.Nil(t, err) require.NoError(t, err)
assert.Equal(t, "100m", r.Requests.Cpu().String()) assert.Equal(t, "100m", r.Requests.Cpu().String())
assert.Equal(t, "1Gi", r.Requests.Memory().String()) assert.Equal(t, "1Gi", r.Requests.Memory().String())
}) })
@ -163,7 +164,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -173,6 +173,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--log-as-json", "--log-as-json",
"--enable-mtls", "--enable-mtls",
} }
@ -237,7 +238,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -247,6 +247,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--log-as-json", "--log-as-json",
"--enable-mtls", "--enable-mtls",
} }
@ -311,7 +312,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "", "--placement-host-address", "",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -321,6 +321,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--log-as-json", "--log-as-json",
"--enable-mtls", "--enable-mtls",
} }
@ -383,7 +384,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "", "--placement-host-address", "",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -393,6 +393,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--log-as-json", "--log-as-json",
"--enable-mtls", "--enable-mtls",
} }
@ -456,7 +457,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "some-host:50000", "--placement-host-address", "some-host:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -466,6 +466,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--log-as-json", "--log-as-json",
"--enable-mtls", "--enable-mtls",
} }
@ -511,7 +512,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -521,6 +521,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--enable-mtls", "--enable-mtls",
} }
@ -554,7 +555,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -564,6 +564,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--enable-mtls", "--enable-mtls",
} }
@ -597,7 +598,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -607,6 +607,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "5", "--dapr-graceful-shutdown-seconds", "5",
"--disable-builtin-k8s-secret-store=false", "--disable-builtin-k8s-secret-store=false",
"--config", defaultTestConfig,
"--enable-mtls", "--enable-mtls",
} }
@ -684,7 +685,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -694,6 +694,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=true", "--disable-builtin-k8s-secret-store=true",
"--config", defaultTestConfig,
"--enable-mtls", "--enable-mtls",
} }
@ -730,7 +731,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -740,6 +740,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=true", "--disable-builtin-k8s-secret-store=true",
"--config", defaultTestConfig,
"--enable-mtls", "--enable-mtls",
} }
@ -764,7 +765,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -774,6 +774,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=true", "--disable-builtin-k8s-secret-store=true",
"--config", defaultTestConfig,
"--enable-api-logging=true", "--enable-api-logging=true",
"--enable-mtls", "--enable-mtls",
} }
@ -799,7 +800,6 @@ func TestGetSidecarContainer(t *testing.T) {
"--control-plane-address", "controlplane:9000", "--control-plane-address", "controlplane:9000",
"--app-protocol", "http", "--app-protocol", "http",
"--placement-host-address", "placement:50000", "--placement-host-address", "placement:50000",
"--config", defaultTestConfig,
"--log-level", "info", "--log-level", "info",
"--app-max-concurrency", "-1", "--app-max-concurrency", "-1",
"--sentry-address", "sentry:50000", "--sentry-address", "sentry:50000",
@ -809,6 +809,7 @@ func TestGetSidecarContainer(t *testing.T) {
"--dapr-http-read-buffer-size", "-1", "--dapr-http-read-buffer-size", "-1",
"--dapr-graceful-shutdown-seconds", "-1", "--dapr-graceful-shutdown-seconds", "-1",
"--disable-builtin-k8s-secret-store=true", "--disable-builtin-k8s-secret-store=true",
"--config", defaultTestConfig,
"--enable-api-logging=false", "--enable-api-logging=false",
"--enable-mtls", "--enable-mtls",
} }

View File

@ -33,6 +33,6 @@ func LoadConfiguration(name string, client client.Client) (*Config, error) {
return nil, err return nil, err
} }
return &Config{ return &Config{
MTLSEnabled: conf.Spec.MTLSSpec.Enabled, MTLSEnabled: conf.Spec.MTLSSpec.GetEnabled(),
}, nil }, nil
} }

View File

@ -38,6 +38,7 @@ import (
"github.com/dapr/dapr/pkg/runtime/security" "github.com/dapr/dapr/pkg/runtime/security"
"github.com/dapr/dapr/pkg/validation" "github.com/dapr/dapr/pkg/validation"
"github.com/dapr/dapr/utils" "github.com/dapr/dapr/utils"
"github.com/dapr/kit/ptr"
) )
const ( const (
@ -95,7 +96,7 @@ type Config struct {
AppHealthThreshold int AppHealthThreshold int
EnableAppHealthCheck bool EnableAppHealthCheck bool
Mode string Mode string
ConfigPath string Config []string
UnixDomainSocket string UnixDomainSocket string
DaprHTTPReadBufferSize int DaprHTTPReadBufferSize int
DisableBuiltinK8sSecretStore bool DisableBuiltinK8sSecretStore bool
@ -127,7 +128,7 @@ type internalConfig struct {
gracefulShutdownDuration time.Duration gracefulShutdownDuration time.Duration
enableAPILogging *bool enableAPILogging *bool
disableBuiltinK8sSecretStore bool disableBuiltinK8sSecretStore bool
configPath string config []string
certChain *credentials.CertChain certChain *credentials.CertChain
} }
@ -166,9 +167,6 @@ func FromConfig(cfg *Config) (*DaprRuntime, error) {
return nil, err return nil, err
} }
var globalConfig *config.Configuration
var configErr error
if intc.mTLSEnabled || intc.mode == modes.KubernetesMode { if intc.mTLSEnabled || intc.mode == modes.KubernetesMode {
intc.certChain, err = security.GetCertChain() intc.certChain, err = security.GetCertChain()
if err != nil { if err != nil {
@ -188,18 +186,26 @@ func FromConfig(cfg *Config) (*DaprRuntime, error) {
operatorClient = client operatorClient = client
} }
var accessControlList *config.AccessControlList
namespace := os.Getenv("NAMESPACE") namespace := os.Getenv("NAMESPACE")
podName := os.Getenv("POD_NAME") podName := os.Getenv("POD_NAME")
if intc.configPath != "" { var (
globalConfig *config.Configuration
configErr error
)
if len(intc.config) > 0 {
switch intc.mode { switch intc.mode {
case modes.KubernetesMode: case modes.KubernetesMode:
log.Debug("Loading Kubernetes config resource: " + intc.configPath) if len(intc.config) > 1 {
globalConfig, configErr = config.LoadKubernetesConfiguration(intc.configPath, namespace, podName, operatorClient) // We are not returning an error here because in Kubernetes mode, the injector itself doesn't allow multiple configuration flags to be added, so this should never happen in normal environments
log.Warnf("Multiple configurations are not supported in Kubernetes mode; only the first one will be loaded")
}
log.Debug("Loading Kubernetes config resource: " + intc.config[0])
globalConfig, configErr = config.LoadKubernetesConfiguration(intc.config[0], namespace, podName, operatorClient)
case modes.StandaloneMode: case modes.StandaloneMode:
log.Debug("Loading config from file: " + intc.configPath) log.Debug("Loading config from file(s): " + strings.Join(intc.config, ", "))
globalConfig, _, configErr = config.LoadStandaloneConfiguration(intc.configPath) globalConfig, configErr = config.LoadStandaloneConfiguration(intc.config...)
} }
} }
@ -218,8 +224,9 @@ func FromConfig(cfg *Config) (*DaprRuntime, error) {
} }
// Initialize metrics only if MetricSpec is enabled. // Initialize metrics only if MetricSpec is enabled.
if globalConfig.Spec.MetricSpec.Enabled { metricsSpec := globalConfig.GetMetricsSpec()
if mErr := diag.InitMetrics(intc.id, namespace, globalConfig.Spec.MetricSpec.Rules); mErr != nil { if metricsSpec.GetEnabled() {
if mErr := diag.InitMetrics(intc.id, namespace, metricsSpec.Rules); mErr != nil {
log.Errorf(rterrors.NewInit(rterrors.InitFailure, "metrics", mErr).Error()) log.Errorf(rterrors.NewInit(rterrors.InitFailure, "metrics", mErr).Error())
} }
} }
@ -241,7 +248,7 @@ func FromConfig(cfg *Config) (*DaprRuntime, error) {
} }
} }
accessControlList, err = acl.ParseAccessControlSpec( accessControlList, err := acl.ParseAccessControlSpec(
globalConfig.Spec.AccessControlSpec, globalConfig.Spec.AccessControlSpec,
intc.appConnectionConfig.Protocol.IsHTTP(), intc.appConnectionConfig.Protocol.IsHTTP(),
) )
@ -251,7 +258,7 @@ func FromConfig(cfg *Config) (*DaprRuntime, error) {
// API logging can be enabled for this app or for every app, globally in the config // API logging can be enabled for this app or for every app, globally in the config
if intc.enableAPILogging == nil { if intc.enableAPILogging == nil {
intc.enableAPILogging = &globalConfig.Spec.LoggingSpec.APILogging.Enabled intc.enableAPILogging = ptr.Of(globalConfig.GetAPILoggingSpec().Enabled)
} }
return newDaprRuntime(intc, globalConfig, accessControlList, resiliencyProvider), nil return newDaprRuntime(intc, globalConfig, accessControlList, resiliencyProvider), nil
@ -261,7 +268,7 @@ func (c *Config) toInternal() (*internalConfig, error) {
intc := &internalConfig{ intc := &internalConfig{
id: c.AppID, id: c.AppID,
mode: modes.DaprMode(c.Mode), mode: modes.DaprMode(c.Mode),
configPath: c.ConfigPath, config: c.Config,
sentryServiceAddress: c.SentryAddress, sentryServiceAddress: c.SentryAddress,
allowedOrigins: c.AllowedOrigins, allowedOrigins: c.AllowedOrigins,
kubernetes: configmodes.KubernetesConfig{ kubernetes: configmodes.KubernetesConfig{

View File

@ -281,7 +281,7 @@ func newDaprRuntime(runtimeConfig *internalConfig, globalConfig *config.Configur
} }
rt.componentAuthorizers = []ComponentAuthorizer{rt.namespaceComponentAuthorizer} rt.componentAuthorizers = []ComponentAuthorizer{rt.namespaceComponentAuthorizer}
if globalConfig != nil && len(globalConfig.Spec.ComponentsSpec.Deny) > 0 { if globalConfig != nil && globalConfig.Spec.ComponentsSpec != nil && len(globalConfig.Spec.ComponentsSpec.Deny) > 0 {
dl := newComponentDenyList(globalConfig.Spec.ComponentsSpec.Deny) dl := newComponentDenyList(globalConfig.Spec.ComponentsSpec.Deny)
rt.componentAuthorizers = append(rt.componentAuthorizers, dl.IsAllowed) rt.componentAuthorizers = append(rt.componentAuthorizers, dl.IsAllowed)
} }
@ -345,7 +345,7 @@ func (a *DaprRuntime) getOperatorClient() (operatorv1pb.OperatorClient, error) {
// setupTracing set up the trace exporters. Technically we don't need to pass `hostAddress` in, // setupTracing set up the trace exporters. Technically we don't need to pass `hostAddress` in,
// but we do so here to explicitly call out the dependency on having `hostAddress` computed. // but we do so here to explicitly call out the dependency on having `hostAddress` computed.
func (a *DaprRuntime) setupTracing(hostAddress string, tpStore tracerProviderStore) error { func (a *DaprRuntime) setupTracing(hostAddress string, tpStore tracerProviderStore) error {
tracingSpec := a.globalConfig.Spec.TracingSpec tracingSpec := a.globalConfig.GetTracingSpec()
// Register stdout trace exporter if user wants to debug requests or log as Info level. // Register stdout trace exporter if user wants to debug requests or log as Info level.
if tracingSpec.Stdout { if tracingSpec.Stdout {
@ -353,7 +353,7 @@ func (a *DaprRuntime) setupTracing(hostAddress string, tpStore tracerProviderSto
} }
// Register zipkin trace exporter if ZipkinSpec is specified // Register zipkin trace exporter if ZipkinSpec is specified
if tracingSpec.Zipkin.EndpointAddress != "" { if tracingSpec.Zipkin != nil && tracingSpec.Zipkin.EndpointAddress != "" {
zipkinExporter, err := zipkin.New(tracingSpec.Zipkin.EndpointAddress) zipkinExporter, err := zipkin.New(tracingSpec.Zipkin.EndpointAddress)
if err != nil { if err != nil {
return err return err
@ -362,24 +362,23 @@ func (a *DaprRuntime) setupTracing(hostAddress string, tpStore tracerProviderSto
} }
// Register otel trace exporter if OtelSpec is specified // Register otel trace exporter if OtelSpec is specified
if tracingSpec.Otel.EndpointAddress != "" && tracingSpec.Otel.Protocol != "" { if tracingSpec.Otel != nil && tracingSpec.Otel.EndpointAddress != "" && tracingSpec.Otel.Protocol != "" {
endpoint := tracingSpec.Otel.EndpointAddress endpoint := tracingSpec.Otel.EndpointAddress
protocol := tracingSpec.Otel.Protocol protocol := tracingSpec.Otel.Protocol
if protocol != "http" && protocol != "grpc" { if protocol != "http" && protocol != "grpc" {
return fmt.Errorf("invalid protocol %v provided for Otel endpoint", protocol) return fmt.Errorf("invalid protocol %v provided for Otel endpoint", protocol)
} }
isSecure := tracingSpec.Otel.IsSecure
var client otlptrace.Client var client otlptrace.Client
if protocol == "http" { if protocol == "http" {
clientOptions := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endpoint)} clientOptions := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endpoint)}
if !isSecure { if !tracingSpec.Otel.GetIsSecure() {
clientOptions = append(clientOptions, otlptracehttp.WithInsecure()) clientOptions = append(clientOptions, otlptracehttp.WithInsecure())
} }
client = otlptracehttp.NewClient(clientOptions...) client = otlptracehttp.NewClient(clientOptions...)
} else { } else {
clientOptions := []otlptracegrpc.Option{otlptracegrpc.WithEndpoint(endpoint)} clientOptions := []otlptracegrpc.Option{otlptracegrpc.WithEndpoint(endpoint)}
if !isSecure { if !tracingSpec.Otel.GetIsSecure() {
clientOptions = append(clientOptions, otlptracegrpc.WithInsecure()) clientOptions = append(clientOptions, otlptracegrpc.WithInsecure())
} }
client = otlptracegrpc.NewClient(clientOptions...) client = otlptracegrpc.NewClient(clientOptions...)
@ -666,50 +665,59 @@ func (a *DaprRuntime) appHealthChanged(status uint8) {
func (a *DaprRuntime) populateSecretsConfiguration() { func (a *DaprRuntime) populateSecretsConfiguration() {
// Populate in a map for easy lookup by store name. // Populate in a map for easy lookup by store name.
if a.globalConfig.Spec.Secrets == nil {
return
}
for _, scope := range a.globalConfig.Spec.Secrets.Scopes { for _, scope := range a.globalConfig.Spec.Secrets.Scopes {
a.compStore.AddSecretsConfiguration(scope.StoreName, scope) a.compStore.AddSecretsConfiguration(scope.StoreName, scope)
} }
} }
func (a *DaprRuntime) buildHTTPPipelineForSpec(spec config.PipelineSpec, targetPipeline string) (pipeline httpMiddleware.Pipeline, err error) { func (a *DaprRuntime) buildHTTPPipelineForSpec(spec config.PipelineSpec, targetPipeline string) (pipeline httpMiddleware.Pipeline, err error) {
if a.globalConfig != nil { pipeline.Handlers = make([]func(next nethttp.Handler) nethttp.Handler, 0, len(spec.Handlers))
pipeline.Handlers = make([]func(next nethttp.Handler) nethttp.Handler, 0, len(spec.Handlers)) for i := 0; i < len(spec.Handlers); i++ {
for i := 0; i < len(spec.Handlers); i++ { middlewareSpec := spec.Handlers[i]
middlewareSpec := spec.Handlers[i] component, exists := a.compStore.GetComponent(middlewareSpec.Type, middlewareSpec.Name)
component, exists := a.compStore.GetComponent(middlewareSpec.Type, middlewareSpec.Name) if !exists {
if !exists { // Log the error but continue with initializing the pipeline
// Log the error but continue with initializing the pipeline log.Error("couldn't find middleware component defined in configuration with name %s and type %s/%s",
log.Error("couldn't find middleware component defined in configuration with name %s and type %s/%s", middlewareSpec.Name, middlewareSpec.Type, middlewareSpec.Version)
middlewareSpec.Name, middlewareSpec.Type, middlewareSpec.Version) continue
continue
}
md := middleware.Metadata{Base: a.toBaseMetadata(component)}
handler, err := a.httpMiddlewareRegistry.Create(middlewareSpec.Type, middlewareSpec.Version, md, middlewareSpec.LogName())
if err != nil {
e := fmt.Sprintf("process component %s error: %s", component.Name, err.Error())
if !component.Spec.IgnoreErrors {
log.Warn("error processing middleware component, daprd process will exit gracefully")
a.Shutdown(a.runtimeConfig.gracefulShutdownDuration)
log.Fatal(e)
// This error is only caught by tests, since during normal execution we panic
return pipeline, errors.New("dapr panicked")
}
log.Error(e)
continue
}
log.Infof("enabled %s/%s %s middleware", middlewareSpec.Type, targetPipeline, middlewareSpec.Version)
pipeline.Handlers = append(pipeline.Handlers, handler)
} }
md := middleware.Metadata{Base: a.toBaseMetadata(component)}
handler, err := a.httpMiddlewareRegistry.Create(middlewareSpec.Type, middlewareSpec.Version, md, middlewareSpec.LogName())
if err != nil {
e := fmt.Sprintf("process component %s error: %s", component.Name, err.Error())
if !component.Spec.IgnoreErrors {
log.Warn("error processing middleware component, daprd process will exit gracefully")
a.Shutdown(a.runtimeConfig.gracefulShutdownDuration)
log.Fatal(e)
// This error is only caught by tests, since during normal execution we panic
return pipeline, errors.New("dapr panicked")
}
log.Error(e)
continue
}
log.Infof("enabled %s/%s %s middleware", middlewareSpec.Type, targetPipeline, middlewareSpec.Version)
pipeline.Handlers = append(pipeline.Handlers, handler)
} }
return pipeline, nil return pipeline, nil
} }
func (a *DaprRuntime) buildHTTPPipeline() (httpMiddleware.Pipeline, error) { func (a *DaprRuntime) buildHTTPPipeline() (httpMiddleware.Pipeline, error) {
return a.buildHTTPPipelineForSpec(a.globalConfig.Spec.HTTPPipelineSpec, "http") if a.globalConfig == nil || a.globalConfig.Spec.HTTPPipelineSpec == nil {
return httpMiddleware.Pipeline{}, nil
}
return a.buildHTTPPipelineForSpec(*a.globalConfig.Spec.HTTPPipelineSpec, "http")
} }
func (a *DaprRuntime) buildAppHTTPPipeline() (httpMiddleware.Pipeline, error) { func (a *DaprRuntime) buildAppHTTPPipeline() (httpMiddleware.Pipeline, error) {
return a.buildHTTPPipelineForSpec(a.globalConfig.Spec.AppHTTPPipelineSpec, "app channel") if a.globalConfig == nil || a.globalConfig.Spec.AppHTTPPipelineSpec == nil {
return httpMiddleware.Pipeline{}, nil
}
return a.buildHTTPPipelineForSpec(*a.globalConfig.Spec.AppHTTPPipelineSpec, "app channel")
} }
func (a *DaprRuntime) initBinding(c componentsV1alpha1.Component) error { func (a *DaprRuntime) initBinding(c componentsV1alpha1.Component) error {
@ -1537,7 +1545,7 @@ func (a *DaprRuntime) startHTTPServer(port int, publicPort *int, profilePort int
PubsubAdapter: a.getPublishAdapter(), PubsubAdapter: a.getPublishAdapter(),
Actors: a.actor, Actors: a.actor,
SendToOutputBindingFn: a.sendToOutputBinding, SendToOutputBindingFn: a.sendToOutputBinding,
TracingSpec: a.globalConfig.Spec.TracingSpec, TracingSpec: a.globalConfig.GetTracingSpec(),
Shutdown: a.ShutdownWithWait, Shutdown: a.ShutdownWithWait,
GetComponentsCapabilitiesFn: a.getComponentsCapabilitesMap, GetComponentsCapabilitiesFn: a.getComponentsCapabilitesMap,
MaxRequestBodySize: int64(a.runtimeConfig.maxRequestBodySize) << 20, // Convert from MB to bytes MaxRequestBodySize: int64(a.runtimeConfig.maxRequestBodySize) << 20, // Convert from MB to bytes
@ -1559,17 +1567,17 @@ func (a *DaprRuntime) startHTTPServer(port int, publicPort *int, profilePort int
UnixDomainSocket: a.runtimeConfig.unixDomainSocket, UnixDomainSocket: a.runtimeConfig.unixDomainSocket,
ReadBufferSizeKB: a.runtimeConfig.readBufferSize, ReadBufferSizeKB: a.runtimeConfig.readBufferSize,
EnableAPILogging: *a.runtimeConfig.enableAPILogging, EnableAPILogging: *a.runtimeConfig.enableAPILogging,
APILoggingObfuscateURLs: a.globalConfig.Spec.LoggingSpec.APILogging.ObfuscateURLs, APILoggingObfuscateURLs: a.globalConfig.GetAPILoggingSpec().ObfuscateURLs,
APILogHealthChecks: !a.globalConfig.Spec.LoggingSpec.APILogging.OmitHealthChecks, APILogHealthChecks: !a.globalConfig.GetAPILoggingSpec().OmitHealthChecks,
} }
server := http.NewServer(http.NewServerOpts{ server := http.NewServer(http.NewServerOpts{
API: a.daprHTTPAPI, API: a.daprHTTPAPI,
Config: serverConf, Config: serverConf,
TracingSpec: a.globalConfig.Spec.TracingSpec, TracingSpec: a.globalConfig.GetTracingSpec(),
MetricSpec: a.globalConfig.Spec.MetricSpec, MetricSpec: a.globalConfig.GetMetricsSpec(),
Pipeline: pipeline, Pipeline: pipeline,
APISpec: a.globalConfig.Spec.APISpec, APISpec: a.globalConfig.GetAPISpec(),
}) })
if err := server.StartNonBlocking(); err != nil { if err := server.StartNonBlocking(); err != nil {
return err return err
@ -1582,7 +1590,7 @@ func (a *DaprRuntime) startHTTPServer(port int, publicPort *int, profilePort int
func (a *DaprRuntime) startGRPCInternalServer(api grpc.API, port int) error { func (a *DaprRuntime) startGRPCInternalServer(api grpc.API, port int) error {
// Since GRPCInteralServer is encrypted & authenticated, it is safe to listen on * // Since GRPCInteralServer is encrypted & authenticated, it is safe to listen on *
serverConf := a.getNewServerConfig([]string{""}, port) serverConf := a.getNewServerConfig([]string{""}, port)
server := grpc.NewInternalServer(api, serverConf, a.globalConfig.Spec.TracingSpec, a.globalConfig.Spec.MetricSpec, a.authenticator, a.proxy) server := grpc.NewInternalServer(api, serverConf, a.globalConfig.GetTracingSpec(), a.globalConfig.GetMetricsSpec(), a.authenticator, a.proxy)
if err := server.StartNonBlocking(); err != nil { if err := server.StartNonBlocking(); err != nil {
return err return err
} }
@ -1593,7 +1601,7 @@ func (a *DaprRuntime) startGRPCInternalServer(api grpc.API, port int) error {
func (a *DaprRuntime) startGRPCAPIServer(api grpc.API, port int) error { func (a *DaprRuntime) startGRPCAPIServer(api grpc.API, port int) error {
serverConf := a.getNewServerConfig(a.runtimeConfig.apiListenAddresses, port) serverConf := a.getNewServerConfig(a.runtimeConfig.apiListenAddresses, port)
server := grpc.NewAPIServer(api, serverConf, a.globalConfig.Spec.TracingSpec, a.globalConfig.Spec.MetricSpec, a.globalConfig.Spec.APISpec, a.proxy, a.workflowEngine) server := grpc.NewAPIServer(api, serverConf, a.globalConfig.GetTracingSpec(), a.globalConfig.GetMetricsSpec(), a.globalConfig.GetAPISpec(), a.proxy, a.workflowEngine)
if err := server.StartNonBlocking(); err != nil { if err := server.StartNonBlocking(); err != nil {
return err return err
} }
@ -1632,7 +1640,7 @@ func (a *DaprRuntime) getGRPCAPI() grpc.API {
DirectMessaging: a.directMessaging, DirectMessaging: a.directMessaging,
Actors: a.actor, Actors: a.actor,
SendToOutputBindingFn: a.sendToOutputBinding, SendToOutputBindingFn: a.sendToOutputBinding,
TracingSpec: a.globalConfig.Spec.TracingSpec, TracingSpec: a.globalConfig.GetTracingSpec(),
AccessControlList: a.accessControlList, AccessControlList: a.accessControlList,
Shutdown: a.ShutdownWithWait, Shutdown: a.ShutdownWithWait,
GetComponentsCapabilitiesFn: a.getComponentsCapabilitesMap, GetComponentsCapabilitiesFn: a.getComponentsCapabilitesMap,
@ -2240,8 +2248,11 @@ func (a *DaprRuntime) initNameResolution() error {
var err error var err error
resolverMetadata := nr.Metadata{} resolverMetadata := nr.Metadata{}
resolverName := a.globalConfig.Spec.NameResolutionSpec.Component var resolverName, resolverVersion string
resolverVersion := a.globalConfig.Spec.NameResolutionSpec.Version if a.globalConfig.Spec.NameResolutionSpec != nil {
resolverName = a.globalConfig.Spec.NameResolutionSpec.Component
resolverVersion = a.globalConfig.Spec.NameResolutionSpec.Version
}
if resolverName == "" { if resolverName == "" {
switch a.runtimeConfig.mode { switch a.runtimeConfig.mode {
@ -2262,7 +2273,9 @@ func (a *DaprRuntime) initNameResolution() error {
fName := utils.ComponentLogName(resolverName, "nameResolution", resolverVersion) fName := utils.ComponentLogName(resolverName, "nameResolution", resolverVersion)
resolver, err = a.nameResolutionRegistry.Create(resolverName, resolverVersion, fName) resolver, err = a.nameResolutionRegistry.Create(resolverName, resolverVersion, fName)
resolverMetadata.Name = resolverName resolverMetadata.Name = resolverName
resolverMetadata.Configuration = a.globalConfig.Spec.NameResolutionSpec.Configuration if a.globalConfig.Spec.NameResolutionSpec != nil {
resolverMetadata.Configuration = a.globalConfig.Spec.NameResolutionSpec.Configuration
}
resolverMetadata.Properties = map[string]string{ resolverMetadata.Properties = map[string]string{
nr.DaprHTTPPort: strconv.Itoa(a.runtimeConfig.httpPort), nr.DaprHTTPPort: strconv.Itoa(a.runtimeConfig.httpPort),
nr.DaprPort: strconv.Itoa(a.runtimeConfig.internalGRPCPort), nr.DaprPort: strconv.Itoa(a.runtimeConfig.internalGRPCPort),
@ -2578,7 +2591,7 @@ func (a *DaprRuntime) initActors() error {
GRPCConnectionFn: a.grpc.GetGRPCConnection, GRPCConnectionFn: a.grpc.GetGRPCConnection,
Config: actorConfig, Config: actorConfig,
CertChain: a.runtimeConfig.certChain, CertChain: a.runtimeConfig.certChain,
TracingSpec: a.globalConfig.Spec.TracingSpec, TracingSpec: a.globalConfig.GetTracingSpec(),
Resiliency: a.resiliency, Resiliency: a.resiliency,
StateStoreName: a.actorStateStoreName, StateStoreName: a.actorStateStoreName,
CompStore: a.compStore, CompStore: a.compStore,
@ -3271,7 +3284,7 @@ func (a *DaprRuntime) getAppHTTPChannelConfig(pipeline httpMiddleware.Pipeline,
CompStore: a.compStore, CompStore: a.compStore,
MaxConcurrency: a.runtimeConfig.appConnectionConfig.MaxConcurrency, MaxConcurrency: a.runtimeConfig.appConnectionConfig.MaxConcurrency,
Pipeline: pipeline, Pipeline: pipeline,
TracingSpec: a.globalConfig.Spec.TracingSpec, TracingSpec: a.globalConfig.GetTracingSpec(),
MaxRequestBodySizeMB: a.runtimeConfig.maxRequestBodySize, MaxRequestBodySizeMB: a.runtimeConfig.maxRequestBodySize,
} }
@ -3534,7 +3547,7 @@ func pubsubTopicKey(componentName, topicName string) string {
func createGRPCManager(runtimeConfig *internalConfig, globalConfig *config.Configuration) *grpc.Manager { func createGRPCManager(runtimeConfig *internalConfig, globalConfig *config.Configuration) *grpc.Manager {
grpcAppChannelConfig := &grpc.AppChannelConfig{} grpcAppChannelConfig := &grpc.AppChannelConfig{}
if globalConfig != nil { if globalConfig != nil {
grpcAppChannelConfig.TracingSpec = globalConfig.Spec.TracingSpec grpcAppChannelConfig.TracingSpec = globalConfig.GetTracingSpec()
grpcAppChannelConfig.AllowInsecureTLS = globalConfig.IsFeatureEnabled(config.AppChannelAllowInsecureTLS) grpcAppChannelConfig.AllowInsecureTLS = globalConfig.IsFeatureEnabled(config.AppChannelAllowInsecureTLS)
} }
if runtimeConfig != nil { if runtimeConfig != nil {

View File

@ -931,7 +931,9 @@ func TestInitNameResolution(t *testing.T) {
rt := NewTestDaprRuntime(modes.StandaloneMode) rt := NewTestDaprRuntime(modes.StandaloneMode)
// target resolver // target resolver
rt.globalConfig.Spec.NameResolutionSpec.Component = "targetResolver" rt.globalConfig.Spec.NameResolutionSpec = &config.NameResolutionSpec{
Component: "targetResolver",
}
// registered resolver // registered resolver
initMockResolverForRuntime(rt, "anotherResolver", nil) initMockResolverForRuntime(rt, "anotherResolver", nil)
@ -948,7 +950,9 @@ func TestInitNameResolution(t *testing.T) {
rt := NewTestDaprRuntime(modes.StandaloneMode) rt := NewTestDaprRuntime(modes.StandaloneMode)
// target resolver // target resolver
rt.globalConfig.Spec.NameResolutionSpec.Component = "someResolver" rt.globalConfig.Spec.NameResolutionSpec = &config.NameResolutionSpec{
Component: "someResolver",
}
// registered resolver // registered resolver
initMockResolverForRuntime(rt, "someResolver", nil) initMockResolverForRuntime(rt, "someResolver", nil)
@ -965,7 +969,24 @@ func TestInitNameResolution(t *testing.T) {
rt := NewTestDaprRuntime(modes.StandaloneMode) rt := NewTestDaprRuntime(modes.StandaloneMode)
// target resolver // target resolver
rt.globalConfig.Spec.NameResolutionSpec.Component = "" rt.globalConfig.Spec.NameResolutionSpec = &config.NameResolutionSpec{}
// registered resolver
initMockResolverForRuntime(rt, "mdns", nil)
// act
err := rt.initNameResolution()
// assert
assert.NoError(t, err, "expected no error")
})
t.Run("test init nameresolution nil in StandaloneMode", func(t *testing.T) {
// given
rt := NewTestDaprRuntime(modes.StandaloneMode)
// target resolver
rt.globalConfig.Spec.NameResolutionSpec = nil
// registered resolver // registered resolver
initMockResolverForRuntime(rt, "mdns", nil) initMockResolverForRuntime(rt, "mdns", nil)
@ -982,7 +1003,24 @@ func TestInitNameResolution(t *testing.T) {
rt := NewTestDaprRuntime(modes.KubernetesMode) rt := NewTestDaprRuntime(modes.KubernetesMode)
// target resolver // target resolver
rt.globalConfig.Spec.NameResolutionSpec.Component = "" rt.globalConfig.Spec.NameResolutionSpec = &config.NameResolutionSpec{}
// registered resolver
initMockResolverForRuntime(rt, "kubernetes", nil)
// act
err := rt.initNameResolution()
// assert
assert.NoError(t, err, "expected no error")
})
t.Run("test init nameresolution nil in KubernetesMode", func(t *testing.T) {
// given
rt := NewTestDaprRuntime(modes.KubernetesMode)
// target resolver
rt.globalConfig.Spec.NameResolutionSpec = nil
// registered resolver // registered resolver
initMockResolverForRuntime(rt, "kubernetes", nil) initMockResolverForRuntime(rt, "kubernetes", nil)
@ -1014,7 +1052,7 @@ func TestSetupTracing(t *testing.T) {
}, { }, {
name: "bad host address, failing zipkin", name: "bad host address, failing zipkin",
tracingConfig: config.TracingSpec{ tracingConfig: config.TracingSpec{
Zipkin: config.ZipkinSpec{ Zipkin: &config.ZipkinSpec{
EndpointAddress: "localhost", EndpointAddress: "localhost",
}, },
}, },
@ -1022,7 +1060,7 @@ func TestSetupTracing(t *testing.T) {
}, { }, {
name: "zipkin trace exporter", name: "zipkin trace exporter",
tracingConfig: config.TracingSpec{ tracingConfig: config.TracingSpec{
Zipkin: config.ZipkinSpec{ Zipkin: &config.ZipkinSpec{
EndpointAddress: "http://foo.bar", EndpointAddress: "http://foo.bar",
}, },
}, },
@ -1030,9 +1068,9 @@ func TestSetupTracing(t *testing.T) {
}, { }, {
name: "otel trace http exporter", name: "otel trace http exporter",
tracingConfig: config.TracingSpec{ tracingConfig: config.TracingSpec{
Otel: config.OtelSpec{ Otel: &config.OtelSpec{
EndpointAddress: "foo.bar", EndpointAddress: "foo.bar",
IsSecure: false, IsSecure: ptr.Of(false),
Protocol: "http", Protocol: "http",
}, },
}, },
@ -1040,9 +1078,9 @@ func TestSetupTracing(t *testing.T) {
}, { }, {
name: "invalid otel trace exporter protocol", name: "invalid otel trace exporter protocol",
tracingConfig: config.TracingSpec{ tracingConfig: config.TracingSpec{
Otel: config.OtelSpec{ Otel: &config.OtelSpec{
EndpointAddress: "foo.bar", EndpointAddress: "foo.bar",
IsSecure: false, IsSecure: ptr.Of(false),
Protocol: "tcp", Protocol: "tcp",
}, },
}, },
@ -1056,12 +1094,12 @@ func TestSetupTracing(t *testing.T) {
}, { }, {
name: "all trace exporters", name: "all trace exporters",
tracingConfig: config.TracingSpec{ tracingConfig: config.TracingSpec{
Otel: config.OtelSpec{ Otel: &config.OtelSpec{
EndpointAddress: "http://foo.bar", EndpointAddress: "http://foo.bar",
IsSecure: false, IsSecure: ptr.Of(false),
Protocol: "http", Protocol: "http",
}, },
Zipkin: config.ZipkinSpec{ Zipkin: &config.ZipkinSpec{
EndpointAddress: "http://foo.bar", EndpointAddress: "http://foo.bar",
}, },
Stdout: true, Stdout: true,
@ -1073,7 +1111,7 @@ func TestSetupTracing(t *testing.T) {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
rt := NewTestDaprRuntime(modes.StandaloneMode) rt := NewTestDaprRuntime(modes.StandaloneMode)
defer stopRuntime(t, rt) defer stopRuntime(t, rt)
rt.globalConfig.Spec.TracingSpec = tc.tracingConfig rt.globalConfig.Spec.TracingSpec = &tc.tracingConfig
if tc.hostAddress != "" { if tc.hostAddress != "" {
rt.hostAddress = tc.hostAddress rt.hostAddress = tc.hostAddress
} }
@ -2458,10 +2496,12 @@ func TestPopulateSecretsConfiguration(t *testing.T) {
// setup // setup
rt := NewTestDaprRuntime(modes.StandaloneMode) rt := NewTestDaprRuntime(modes.StandaloneMode)
defer stopRuntime(t, rt) defer stopRuntime(t, rt)
rt.globalConfig.Spec.Secrets.Scopes = []config.SecretsScope{ rt.globalConfig.Spec.Secrets = &config.SecretsSpec{
{ Scopes: []config.SecretsScope{
StoreName: "testMock", {
DefaultAccess: "allow", StoreName: "testMock",
DefaultAccess: "allow",
},
}, },
} }
@ -6069,10 +6109,10 @@ func initMockStateStoreForRuntime(rt *DaprRuntime, encryptKey string, e error) *
func TestTraceShutdown(t *testing.T) { func TestTraceShutdown(t *testing.T) {
rt := NewTestDaprRuntime(modes.StandaloneMode) rt := NewTestDaprRuntime(modes.StandaloneMode)
rt.runtimeConfig.gracefulShutdownDuration = 5 * time.Second rt.runtimeConfig.gracefulShutdownDuration = 5 * time.Second
rt.globalConfig.Spec.TracingSpec = config.TracingSpec{ rt.globalConfig.Spec.TracingSpec = &config.TracingSpec{
Otel: config.OtelSpec{ Otel: &config.OtelSpec{
EndpointAddress: "foo.bar", EndpointAddress: "foo.bar",
IsSecure: false, IsSecure: ptr.Of(false),
Protocol: "http", Protocol: "http",
}, },
} }

View File

@ -137,7 +137,7 @@ func getKubernetesConfig(configName string) (SentryConfig, error) {
func getSelfhostedConfig(configName string) (SentryConfig, error) { func getSelfhostedConfig(configName string) (SentryConfig, error) {
defaultConfig := getDefaultConfig() defaultConfig := getDefaultConfig()
daprConfig, _, err := daprGlobalConfig.LoadStandaloneConfiguration(configName) daprConfig, err := daprGlobalConfig.LoadStandaloneConfiguration(configName)
if err != nil { if err != nil {
return defaultConfig, err return defaultConfig, err
} }
@ -149,8 +149,9 @@ func getSelfhostedConfig(configName string) (SentryConfig, error) {
} }
func parseConfiguration(conf SentryConfig, daprConfig *daprGlobalConfig.Configuration) (SentryConfig, error) { func parseConfiguration(conf SentryConfig, daprConfig *daprGlobalConfig.Configuration) (SentryConfig, error) {
if daprConfig.Spec.MTLSSpec.WorkloadCertTTL != "" { mtlsSpec := daprConfig.GetMTLSSpec()
d, err := time.ParseDuration(daprConfig.Spec.MTLSSpec.WorkloadCertTTL) if mtlsSpec.WorkloadCertTTL != "" {
d, err := time.ParseDuration(mtlsSpec.WorkloadCertTTL)
if err != nil { if err != nil {
return conf, fmt.Errorf("error parsing WorkloadCertTTL duration: %w", err) return conf, fmt.Errorf("error parsing WorkloadCertTTL duration: %w", err)
} }
@ -158,8 +159,8 @@ func parseConfiguration(conf SentryConfig, daprConfig *daprGlobalConfig.Configur
conf.WorkloadCertTTL = d conf.WorkloadCertTTL = d
} }
if daprConfig.Spec.MTLSSpec.AllowedClockSkew != "" { if mtlsSpec.AllowedClockSkew != "" {
d, err := time.ParseDuration(daprConfig.Spec.MTLSSpec.AllowedClockSkew) d, err := time.ParseDuration(mtlsSpec.AllowedClockSkew)
if err != nil { if err != nil {
return conf, fmt.Errorf("error parsing AllowedClockSkew duration: %w", err) return conf, fmt.Errorf("error parsing AllowedClockSkew duration: %w", err)
} }

View File

@ -26,7 +26,7 @@ func TestConfig(t *testing.T) {
t.Run("parse configuration", func(t *testing.T) { t.Run("parse configuration", func(t *testing.T) {
daprConfig := daprDaprConfig.Configuration{ daprConfig := daprDaprConfig.Configuration{
Spec: daprDaprConfig.ConfigurationSpec{ Spec: daprDaprConfig.ConfigurationSpec{
MTLSSpec: daprDaprConfig.MTLSSpec{ MTLSSpec: &daprDaprConfig.MTLSSpec{
Enabled: true, Enabled: true,
WorkloadCertTTL: "5s", WorkloadCertTTL: "5s",
AllowedClockSkew: "1h", AllowedClockSkew: "1h",

View File

@ -217,7 +217,7 @@ func TestServiceInvocationWithAllowLists(t *testing.T) {
t.Logf("configuration name: daprsystem, get failed: %s \n", err.Error()) t.Logf("configuration name: daprsystem, get failed: %s \n", err.Error())
os.Exit(-1) os.Exit(-1)
} }
if !config.Spec.MTLSSpec.Enabled { if !config.Spec.MTLSSpec.GetEnabled() {
t.Logf("mtls disabled. can't running unit tests") t.Logf("mtls disabled. can't running unit tests")
return return
} }

View File

@ -31,7 +31,7 @@ import (
"github.com/dapr/dapr/tests/runner/summary" "github.com/dapr/dapr/tests/runner/summary"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v3"
) )
var ( var (

View File

@ -11,7 +11,7 @@ code-generate: controller-gen
$(CONTROLLER_GEN) object:headerFile="./tools/boilerplate.go.txt" \ $(CONTROLLER_GEN) object:headerFile="./tools/boilerplate.go.txt" \
crd:crdVersions=v1 paths="./pkg/apis/..." output:crd:artifacts:config=config/crd/bases crd:crdVersions=v1 paths="./pkg/apis/..." output:crd:artifacts:config=config/crd/bases
$(CONTROLLER_GEN) object:headerFile="./tools/boilerplate.go.txt" \ $(CONTROLLER_GEN) object:headerFile="./tools/boilerplate.go.txt" \
paths="./pkg/apis/..." paths="./pkg/apis/..."
# find or download controller-gen # find or download controller-gen
# download controller-gen if necessary # download controller-gen if necessary
@ -21,7 +21,7 @@ ifeq (, $(shell which controller-gen))
set -e ;\ set -e ;\
CONTROLLER_GEN_TMP_DIR="$$(mktemp -d)" ;\ CONTROLLER_GEN_TMP_DIR="$$(mktemp -d)" ;\
cd "$$CONTROLLER_GEN_TMP_DIR" ;\ cd "$$CONTROLLER_GEN_TMP_DIR" ;\
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.5.0 ; \ go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.3 ; \
rm -rf "$$CONTROLLER_GEN_TMP_DIR" ;\ rm -rf "$$CONTROLLER_GEN_TMP_DIR" ;\
} }
CONTROLLER_GEN=$(GOBIN)/controller-gen CONTROLLER_GEN=$(GOBIN)/controller-gen