Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions cmd/server/internal/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,17 @@ type tenantInfo struct {
type serviceCredentials struct {
XSAppName string `json:"xsappname"`
SaasRegistryEnabled bool `json:"saasregistryenabled"`
Plan string `json:"plan"`
UAA *struct {
XSAppName string `json:"xsappname"`
} `json:"uaa"`
}

// Credentials with plan
type serviceMetaInfo struct {
Plan string `json:"plan"`
Credentials serviceCredentials `json:"credentials"`
}

type GetDependenciesAuthError struct{}

func (err *GetDependenciesAuthError) Error() string {
Expand Down Expand Up @@ -833,7 +838,7 @@ func (s *SubscriptionHandler) getSaasDetails(capApp *v1alpha1.CAPApplication, st
info *v1alpha1.ServiceInfo
)
if info, err = s.getServiceInfo(capApp, "saas-registry"); err == nil {
result, err = util.ReadServiceCredentialsFromSecret[util.SaasRegistryCredentials](info, capApp.Namespace, s.KubeClientset)
result, err = util.ReadServiceCredentialsFromSecret[util.SaasRegistryCredentials](info, capApp.Namespace, s.KubeClientset, false)
}
if err != nil {
util.LogError(err, "SaaS Registry credentials could not be read. Exiting..", step, capApp, nil)
Expand All @@ -852,7 +857,7 @@ func (s *SubscriptionHandler) getXSUAADetails(capApp *v1alpha1.CAPApplication, s
if info == nil {
err = fmt.Errorf("could not find service with class %s in CAPApplication %s.%s", "xsuaa", capApp.Namespace, capApp.Name)
} else {
result, err = util.ReadServiceCredentialsFromSecret[util.XSUAACredentials](info, capApp.Namespace, s.KubeClientset)
result, err = util.ReadServiceCredentialsFromSecret[util.XSUAACredentials](info, capApp.Namespace, s.KubeClientset, false)
}

if err != nil {
Expand All @@ -868,7 +873,7 @@ func (s *SubscriptionHandler) getSmsDetails(capApp *v1alpha1.CAPApplication, ste
info *v1alpha1.ServiceInfo
)
if info, err = s.getServiceInfo(capApp, "subscription-manager"); err == nil {
result, err = util.ReadServiceCredentialsFromSecret[util.SmsCredentials](info, capApp.Namespace, s.KubeClientset)
result, err = util.ReadServiceCredentialsFromSecret[util.SmsCredentials](info, capApp.Namespace, s.KubeClientset, false)
}
if err != nil {
util.LogError(err, "SMS credentials could not be read. Exiting..", step, capApp, nil)
Expand Down Expand Up @@ -1154,36 +1159,49 @@ func (c *serviceCredentials) xsAppName() string {
}

func (s *SubscriptionHandler) getServiceDependencies(capApp *v1alpha1.CAPApplication, service v1alpha1.ServiceInfo) map[string]string {
creds, err := util.ReadServiceCredentialsFromSecret[serviceCredentials](&service, capApp.Namespace, s.KubeClientset)
// Read credentials with metadata (as we need a check based on the plan
serviceCredInfo, err := util.ReadServiceCredentialsFromSecret[serviceMetaInfo](&service, capApp.Namespace, s.KubeClientset, true)
if err != nil {
util.LogError(err, "Failed to read secret for service", GetDependencies, capApp, nil, "service", service.Name, "secret", service.Secret)
return nil
}

if isServiceRelevantForDependencies(service, creds) {
if name := creds.xsAppName(); name != "" {
if isServiceRelevantForDependencies(service, serviceCredInfo) {

if name := serviceCredInfo.Credentials.xsAppName(); name != "" {
if isSpecialDependency(service, serviceCredInfo) {
return map[string]string{
"appName": service.Class,
"appId": name,
}
}
return map[string]string{"xsappname": name}
}
}

return nil
}

func isServiceRelevantForDependencies(serviceInfo v1alpha1.ServiceInfo, creds *serviceCredentials) bool {
func isServiceRelevantForDependencies(serviceInfo v1alpha1.ServiceInfo, creds *serviceMetaInfo) bool {
if serviceInfo.GetSubscriptionDependency() == v1alpha1.SubscriptionDependencyAlways {
return true
}

if serviceInfo.GetSubscriptionDependency() == v1alpha1.SubscriptionDependencyAuto {
return serviceInfo.Class == "destination" ||
serviceInfo.Class == "connectivity" ||
(serviceInfo.Class == "auditlog" && creds.Plan == "oauth2") ||
creds.SaasRegistryEnabled
return isSpecialDependency(serviceInfo, creds) ||
creds.Credentials.SaasRegistryEnabled
}

return false
}

// These services might need some special handling for now, until there is some clarity from BTP as to how saas-registry differentiates b/w xsappname and appId/appName dependencies.
func isSpecialDependency(serviceInfo v1alpha1.ServiceInfo, creds *serviceMetaInfo) bool {
return serviceInfo.Class == "destination" ||
serviceInfo.Class == "connectivity" ||
(serviceInfo.Class == "auditlog" && creds.Plan == "oauth2")
}

func (s *SubscriptionHandler) getDependencies(req *http.Request, subscriptionType subscriptionType) ([]byte, error) {
var dependenciesArray []map[string]string

Expand Down
68 changes: 34 additions & 34 deletions cmd/server/internal/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func createSecrets() []runtime.Object {
"sburl": "internal.auth.service.local",
"url": "https://app-domain.auth.service.local",
"saasregistryenabled": true,
"uaa": {"xsappname": "appname!b15" },
"uaa": {"xsappname": "saasappname!b15" },
"credential-type": "instance-secret"
}`),
},
Expand All @@ -130,7 +130,7 @@ func createSecrets() []runtime.Object {
"sburl": "internal.auth.service.local",
"url": "https://app-domain.auth.service.local",
"saasregistryenabled": true,
"uaa": {"xsappname": "appname!b15" },
"uaa": {"xsappname": "destappname!b15" },
"credential-type": "instance-secret"
}`),
},
Expand All @@ -149,7 +149,7 @@ func createSecrets() []runtime.Object {
"sburl": "internal.auth.service.local",
"url": "https://app-domain.auth.service.local",
"saasregistryenabled": true,
"uaa": {"xsappname": "appname!b15" },
"uaa": {"xsappname": "rtappname!b15" },
"credential-type": "instance-secret"
}`),
},
Expand All @@ -168,7 +168,7 @@ func createSecrets() []runtime.Object {
"sburl": "internal.auth.service.local",
"url": "https://app-domain.auth.service.local",
"saasregistryenabled": true,
"xsappname": "appname!b15",
"xsappname": "smappname!b15",
"credential-type": "instance-secret"
}`),
},
Expand Down Expand Up @@ -1641,10 +1641,10 @@ func TestGetDependencies(t *testing.T) {
method: http.MethodGet,
expectedStatusCode: http.StatusOK,
expectedResponse: []map[string]string{
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"appId": "destappname!b15", "appName": "destination"},
{"xsappname": "rtappname!b15"},
},
},
{
Expand All @@ -1657,10 +1657,10 @@ func TestGetDependencies(t *testing.T) {
},
expectedResponse: []map[string]string{
{"xsappname": "appname!b14"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"appId": "destappname!b15", "appName": "destination"},
{"xsappname": "rtappname!b15"},
},
},
{
Expand All @@ -1672,10 +1672,10 @@ func TestGetDependencies(t *testing.T) {
ca.Spec.BTP.Services[0].SubscriptionDependency = &dep // xsuaa: explicit Auto, still not qualified by class/credentials
},
expectedResponse: []map[string]string{
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"appId": "destappname!b15", "appName": "destination"},
{"xsappname": "rtappname!b15"},
},
},
{
Expand All @@ -1687,9 +1687,9 @@ func TestGetDependencies(t *testing.T) {
ca.Spec.BTP.Services[4].SubscriptionDependency = &dep // destination: auto-qualified by class, but Never prevents inclusion
},
expectedResponse: []map[string]string{
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"xsappname": "rtappname!b15"},
},
},
}
Expand Down Expand Up @@ -1776,10 +1776,10 @@ func TestGetSMSDependencies(t *testing.T) {
method: http.MethodGet,
expectedStatusCode: http.StatusOK,
expectedResponse: []map[string]string{
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"appId": "destappname!b15", "appName": "destination"},
{"xsappname": "rtappname!b15"},
},
},
{
Expand All @@ -1792,10 +1792,10 @@ func TestGetSMSDependencies(t *testing.T) {
},
expectedResponse: []map[string]string{
{"xsappname": "appname!b14"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"appId": "destappname!b15", "appName": "destination"},
{"xsappname": "rtappname!b15"},
},
},
{
Expand All @@ -1807,10 +1807,10 @@ func TestGetSMSDependencies(t *testing.T) {
ca.Spec.BTP.Services[0].SubscriptionDependency = &dep // xsuaa: explicit Auto, still not qualified by class/credentials
},
expectedResponse: []map[string]string{
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"appId": "destappname!b15", "appName": "destination"},
{"xsappname": "rtappname!b15"},
},
},
{
Expand All @@ -1822,9 +1822,9 @@ func TestGetSMSDependencies(t *testing.T) {
ca.Spec.BTP.Services[4].SubscriptionDependency = &dep // destination: auto-qualified by class, but Never prevents inclusion
},
expectedResponse: []map[string]string{
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "appname!b15"},
{"xsappname": "saasappname!b15"},
{"xsappname": "smappname!b15"},
{"xsappname": "rtappname!b15"},
},
},
}
Expand Down
11 changes: 8 additions & 3 deletions internal/util/vcap-credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,21 @@ const (
PropertyFormatJSON PropertyFormat = "json"
)

func ReadServiceCredentialsFromSecret[T any](serviceInfo *v1alpha1.ServiceInfo, ns string, kubeClient kubernetes.Interface) (*T, error) {
func ReadServiceCredentialsFromSecret[T any](serviceInfo *v1alpha1.ServiceInfo, ns string, kubeClient kubernetes.Interface, withMeta bool) (*T, error) {
entry, err := CreateVCAPEntryFromSecret(serviceInfo, ns, kubeClient, nil)
if err != nil {
return nil, err
}
b, err := json.Marshal(entry["credentials"])
var serviceCredInfo []byte
if withMeta {
serviceCredInfo, err = json.Marshal(entry)
} else {
serviceCredInfo, err = json.Marshal(entry["credentials"])
}
if err != nil {
return nil, fmt.Errorf("could not serialize credentials for service %s: %s", serviceInfo.Name, err)
}
return ParseJSON[T](b)
return ParseJSON[T](serviceCredInfo)
}

func CreateVCAPEntryFromSecret(serviceInfo *v1alpha1.ServiceInfo, ns string, kubeClient kubernetes.Interface, kubeInformerFactory informers.SharedInformerFactory) (entry map[string]any, err error) {
Expand Down
4 changes: 2 additions & 2 deletions internal/util/vcap-credentials_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func testReadServiceCredentialsFromSecret(t *testing.T) {

// test successful read
secretName := "metadata-with-credential-key"
credentials, err := ReadServiceCredentialsFromSecret[map[string]string](&v1alpha1.ServiceInfo{Name: "service-a", Class: "xyz", Secret: secretName}, "default", c)
credentials, err := ReadServiceCredentialsFromSecret[map[string]string](&v1alpha1.ServiceInfo{Name: "service-a", Class: "xyz", Secret: secretName}, "default", c, false)
if err != nil {
t.Errorf("could not read credentials from secret %s", secretName)
}
Expand All @@ -203,7 +203,7 @@ func testReadServiceCredentialsFromSecret(t *testing.T) {
}

// test with type mismatch
_, err = ReadServiceCredentialsFromSecret[[]string](&v1alpha1.ServiceInfo{Name: "service-a", Class: "xyz", Secret: secretName}, "default", c)
_, err = ReadServiceCredentialsFromSecret[[]string](&v1alpha1.ServiceInfo{Name: "service-a", Class: "xyz", Secret: secretName}, "default", c, false)
if err == nil {
t.Errorf("expected error when reading credentials as array from secret %s", secretName)
}
Expand Down
Loading