Skip to content

Commit

Permalink
Fix license metric options (#250)
Browse files Browse the repository at this point in the history
* Fix license metric options

* Remove unit test

* Add  tests for license annotations

* Add tests for cloudpak annotations

* Fix up tests for new valid license options

* Default metric Fix

* Metric mapping fix

* License tests update

* Hide the license metric field in the UI

* Remove duplicate test setup

Co-authored-by: ilewis <idlewis@users.noreply.github.com>
Co-authored-by: Leo Christy Jesuraj <leojc@ca.ibm.com>
  • Loading branch information
3 people committed Nov 18, 2022
1 parent c5aa116 commit f039f6f
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 24 deletions.
6 changes: 1 addition & 5 deletions api/v1/webspherelibertyapplication_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ type License struct {
ProductEntitlementSource LicenseEntitlement `json:"productEntitlementSource,omitempty"`

// Charge metric code. Defaults to Virtual Processor Core (VPC). Other option: Processor Value Unit (PVU)
// +operator-sdk:csv:customresourcedefinitions:order=102,type=spec,displayName="Metric"
// +operator-sdk:csv:customresourcedefinitions:order=102,type=spec,displayName="Metric",xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden"
Metric LicenseMetric `json:"metric,omitempty"`

// I represent that the software in the above-referenced application container includes the IBM Program referenced below and I accept the terms of the license agreement corresponding
Expand Down Expand Up @@ -1201,10 +1201,6 @@ func (cr *WebSphereLibertyApplication) Initialize() {
if cr.Spec.License.ProductEntitlementSource == "" {
cr.Spec.License.ProductEntitlementSource = LicenseEntitlementStandalone
}
if cr.Spec.License.Metric == "" {
cr.Spec.License.Metric = LicenseMetricVPC
}

}

// GetLabels returns set of labels to be added to all resources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ metadata:
"license": {
"accept": false,
"edition": "IBM WebSphere Application Server",
"metric": "Virtual Processor Core (VPC)",
"productEntitlementSource": "Standalone"
},
"manageTLS": true
Expand Down Expand Up @@ -58,7 +57,7 @@ metadata:
capabilities: Auto Pilot
categories: Application Runtime
containerImage: icr.io/cpopen/websphere-liberty-operator:daily
createdAt: "2022-11-16T14:25:28Z"
createdAt: "2022-11-18T12:08:09Z"
description: Deploy and manage containerized Liberty applications
olm.skipRange: '>=1.0.0 <1.1.0'
operators.openshift.io/infrastructure-features: '["disconnected"]'
Expand Down Expand Up @@ -464,6 +463,8 @@ spec:
- description: 'Charge metric code. Defaults to Virtual Processor Core (VPC). Other option: Processor Value Unit (PVU)'
displayName: Metric
path: license.metric
x-descriptors:
- urn:alm:descriptor:com.tectonic.ui:hidden
- description: I represent that the software in the above-referenced application container includes the IBM Program referenced below and I accept the terms of the license agreement corresponding to the version of IBM Program in the application container by setting this value to true. See https://ibm.biz/was-license for the license agreements applicable to this IBM Program
displayName: Accept License
path: license.accept
Expand Down
24 changes: 24 additions & 0 deletions bundle/tests/scorecard/kuttl/license/00-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: license-wla
status:
replicas: 1
readyReplicas: 1
updatedReplicas: 1
---
apiVersion: v1
kind: Pod
spec:
containers:
- image: icr.io/appcafe/open-liberty/samples/getting-started
status:
containerStatuses:
- ready: true
metadata:
annotations:
test-step: license-00
productChargedContainers: app
productID: e7daacc46bbe4e2dacd2af49145a4723
productName: IBM WebSphere Application Server
productMetric: PROCESSOR_VALUE_UNIT
13 changes: 13 additions & 0 deletions bundle/tests/scorecard/kuttl/license/00-default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test the default values for edition, metric and productEntitlementSource annotations
apiVersion: liberty.websphere.ibm.com/v1
kind: WebSphereLibertyApplication
metadata:
name: license-wla
annotations:
test-step: license-00
spec:
license:
accept: true
applicationImage: icr.io/appcafe/open-liberty/samples/getting-started
replicas: 1

27 changes: 27 additions & 0 deletions bundle/tests/scorecard/kuttl/license/01-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: license-wla
status:
replicas: 1
readyReplicas: 1
updatedReplicas: 1
---
apiVersion: v1
kind: Pod
spec:
containers:
- image: icr.io/appcafe/open-liberty/samples/getting-started
status:
containerStatuses:
- ready: true
metadata:
annotations:
test-step: license-01
productChargedContainers: app
productID: 87f3487c22f34742a799164f3f3ffa78
productName: IBM WebSphere Application Server Liberty Core
productMetric: PROCESSOR_VALUE_UNIT
productCloudpakRatio: 8:1
cloudpakId: be8ae84b3dd04d81b90af0d846849182
cloudpakName: IBM WebSphere Application Server Family Edition
14 changes: 14 additions & 0 deletions bundle/tests/scorecard/kuttl/license/01-core.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: liberty.websphere.ibm.com/v1
kind: WebSphereLibertyApplication
metadata:
name: license-wla
annotations:
test-step: license-01
spec:
license:
accept: true
edition: IBM WebSphere Application Server Liberty Core
productEntitlementSource: IBM WebSphere Application Server Family Edition
applicationImage: icr.io/appcafe/open-liberty/samples/getting-started
replicas: 1

28 changes: 28 additions & 0 deletions bundle/tests/scorecard/kuttl/license/02-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: license-wla
status:
replicas: 1
readyReplicas: 1
updatedReplicas: 1
---
apiVersion: v1
kind: Pod
spec:
containers:
- image: icr.io/appcafe/open-liberty/samples/getting-started
status:
containerStatuses:
- ready: true
metadata:
annotations:
test-step: license-02
productChargedContainers: app
productID: c6a988d93b0f4d1388200d40ddc84e5b
productName: IBM WebSphere Application Server Network Deployment
productMetric: VIRTUAL_PROCESSOR_CORE
productCloudpakRatio: 1:1
cloudpakId: 4df52d2cdc374ba09f631a650ad2b5bf
cloudpakName: IBM Cloud Pak for Applications

14 changes: 14 additions & 0 deletions bundle/tests/scorecard/kuttl/license/02-nd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: liberty.websphere.ibm.com/v1
kind: WebSphereLibertyApplication
metadata:
name: license-wla
annotations:
test-step: license-02
spec:
license:
accept: true
edition: IBM WebSphere Application Server Network Deployment
productEntitlementSource: IBM Cloud Pak for Applications
applicationImage: icr.io/appcafe/open-liberty/samples/getting-started
replicas: 1

Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,8 @@ spec:
- description: 'Charge metric code. Defaults to Virtual Processor Core (VPC). Other option: Processor Value Unit (PVU)'
displayName: Metric
path: license.metric
x-descriptors:
- urn:alm:descriptor:com.tectonic.ui:hidden
- description: I represent that the software in the above-referenced application container includes the IBM Program referenced below and I accept the terms of the license agreement corresponding to the version of IBM Program in the application container by setting this value to true. See https://ibm.biz/was-license for the license agreements applicable to this IBM Program
displayName: Accept License
path: license.accept
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ spec:
accept: false
edition: IBM WebSphere Application Server
productEntitlementSource: Standalone
metric: Virtual Processor Core (VPC)
applicationImage: icr.io/appcafe/open-liberty/samples/getting-started@sha256:3077bf2cb4c2bb4c34a37bf3557e85d508669e0f915c0a95a13f7314a517da35
manageTLS: true
8 changes: 2 additions & 6 deletions controllers/webspherelibertyapplication_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,7 @@ func (r *ReconcileWebSphereLiberty) Reconcile(ctx context.Context, request ctrl.
return err
}
lutils.CustomizeLibertyAnnotations(&statefulSet.Spec.Template, instance)
if err := lutils.CustomizeLicenseAnnotations(&statefulSet.Spec.Template, instance); err != nil {
return err
}
lutils.CustomizeLicenseAnnotations(&statefulSet.Spec.Template, instance)
if instance.Spec.SSO != nil {
err = lutils.CustomizeEnvSSO(&statefulSet.Spec.Template, instance, r.GetClient(), r.IsOpenShift())
if err != nil {
Expand Down Expand Up @@ -526,9 +524,7 @@ func (r *ReconcileWebSphereLiberty) Reconcile(ctx context.Context, request ctrl.
return err
}
lutils.CustomizeLibertyAnnotations(&deploy.Spec.Template, instance)
if err := lutils.CustomizeLicenseAnnotations(&deploy.Spec.Template, instance); err != nil {
return err
}
lutils.CustomizeLicenseAnnotations(&deploy.Spec.Template, instance)
if instance.Spec.SSO != nil {
err = lutils.CustomizeEnvSSO(&deploy.Spec.Template, instance, r.GetClient(), r.IsOpenShift())
if err != nil {
Expand Down
14 changes: 4 additions & 10 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func CustomizeLibertyAnnotations(pts *corev1.PodTemplateSpec, la *wlv1.WebSphere
pts.Annotations = rcoutils.MergeMaps(pts.Annotations, libertyAnnotations)
}

func CustomizeLicenseAnnotations(pts *corev1.PodTemplateSpec, la *wlv1.WebSphereLibertyApplication) error {
func CustomizeLicenseAnnotations(pts *corev1.PodTemplateSpec, la *wlv1.WebSphereLibertyApplication) {
pid := ""
if val, ok := editionProductID[la.Spec.License.Edition]; ok {
pid = val
Expand All @@ -200,13 +200,9 @@ func CustomizeLicenseAnnotations(pts *corev1.PodTemplateSpec, la *wlv1.WebSphere

entitlement := la.Spec.License.ProductEntitlementSource

metricValue := "VIRTUAL_PROCESSOR_CORE"
if la.Spec.License.Metric == wlv1.LicenseMetricPVU {
if entitlement == wlv1.LicenseEntitlementWSHE || entitlement == wlv1.LicenseEntitlementCP4Apps {
return fmt.Errorf("Invalid metric value '%v' is specified for product entitlement source '%v'", la.Spec.License.Metric, entitlement)
} else {
metricValue = "PROCESSOR_VALUE_UNIT"
}
metricValue := "PROCESSOR_VALUE_UNIT"
if entitlement == wlv1.LicenseEntitlementWSHE || entitlement == wlv1.LicenseEntitlementCP4Apps {
metricValue = "VIRTUAL_PROCESSOR_CORE"
}
pts.Annotations["productMetric"] = metricValue

Expand Down Expand Up @@ -236,8 +232,6 @@ func CustomizeLicenseAnnotations(pts *corev1.PodTemplateSpec, la *wlv1.WebSphere
}
pts.Annotations["cloudpakId"] = cloudpakId
}

return nil
}

// findEnvVars checks if the environment variable is already present
Expand Down
141 changes: 141 additions & 0 deletions utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,147 @@ func TestCustomizeEnvSSO(t *testing.T) {
}
}

type licenseTestData struct {
// input from the spec
metric webspherelibertyv1.LicenseMetric
edition webspherelibertyv1.LicenseEdition
pes webspherelibertyv1.LicenseEntitlement
// whether CustomizeLicenseAnnotations is expected to return an err or not
pass bool
}

func TestCustomizeLicenseAnnotations(t *testing.T) {
t.Log("Starting license test")

td := []licenseTestData{}
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionBase, pes: webspherelibertyv1.LicenseEntitlementStandalone})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionBase, pes: webspherelibertyv1.LicenseEntitlementCP4Apps})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionBase, pes: webspherelibertyv1.LicenseEntitlementFamilyEdition})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionBase, pes: webspherelibertyv1.LicenseEntitlementWSHE})

td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionCore, pes: webspherelibertyv1.LicenseEntitlementStandalone})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionCore, pes: webspherelibertyv1.LicenseEntitlementCP4Apps})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionCore, pes: webspherelibertyv1.LicenseEntitlementFamilyEdition})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionCore, pes: webspherelibertyv1.LicenseEntitlementWSHE})

td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionND, pes: webspherelibertyv1.LicenseEntitlementStandalone})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionND, pes: webspherelibertyv1.LicenseEntitlementCP4Apps})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionND, pes: webspherelibertyv1.LicenseEntitlementFamilyEdition})
td = append(td, licenseTestData{edition: webspherelibertyv1.LicenseEditionND, pes: webspherelibertyv1.LicenseEntitlementWSHE})

for _, s := range td {
t.Logf("Testing %#v\n", s)
spec := webspherelibertyv1.WebSphereLibertyApplicationSpec{}
spec.License.Metric = s.metric
spec.License.ProductEntitlementSource = s.pes
spec.License.Edition = s.edition
app := createWebSphereLibertyApp("myapp", "myns", spec)
pts := &corev1.PodTemplateSpec{}
pts.Annotations = make(map[string]string)

CustomizeLicenseAnnotations(pts, app)

// "productChargedContainers" should always be set to 'app'
if pts.Annotations["productChargedContainers"] != "app" {
t.Logf("productChargedContainers: expected 'app' but was %s\n", pts.Annotations["productChargedContainers"])
t.Error("pcc was wrong")
} else {
t.Log("pcc was correct")
}
// 'productMetric' is PVU for Standalone and Family Edition. VPU otherwise.
if s.pes == webspherelibertyv1.LicenseEntitlementStandalone || s.pes == webspherelibertyv1.LicenseEntitlementFamilyEdition {
if pts.Annotations["productMetric"] != "PROCESSOR_VALUE_UNIT" {
t.Errorf("product metric: expected 'PROCESSOR_VALUE_UNIT' but was %s\n", pts.Annotations["productMetric"])
}
} else {
if pts.Annotations["productMetric"] != "VIRTUAL_PROCESSOR_CORE" {
t.Errorf("product metric: expected 'VIRTUAL_PROCESSOR_CORE' but was %s\n", pts.Annotations["productMetric"])
}
}
// 'productID' and 'productName' should always be direct mappings from spec.License.Edition
switch s.edition {
case webspherelibertyv1.LicenseEditionCore:
if pts.Annotations["productID"] != "87f3487c22f34742a799164f3f3ffa78" {
t.Errorf("Incorrect productID for edition core: %s\n", pts.Annotations["productID"])
}
if pts.Annotations["productName"] != "IBM WebSphere Application Server Liberty Core" {
t.Errorf("Incorrect productName for edition core: %s\n", pts.Annotations["productName"])
}
case webspherelibertyv1.LicenseEditionBase:
if pts.Annotations["productID"] != "e7daacc46bbe4e2dacd2af49145a4723" {
t.Errorf("Incorrect productID for edition base: %s\n", pts.Annotations["productID"])
}
if pts.Annotations["productName"] != "IBM WebSphere Application Server" {
t.Errorf("Incorrect productName for edition base: %s\n", pts.Annotations["productName"])
}
case webspherelibertyv1.LicenseEditionND:
if pts.Annotations["productID"] != "c6a988d93b0f4d1388200d40ddc84e5b" {
t.Errorf("Incorrect productID for edition ND: %s\n", pts.Annotations["productID"])
}
if pts.Annotations["productName"] != "IBM WebSphere Application Server Network Deployment" {
t.Errorf("Incorrect productName for edition ND: %s\n", pts.Annotations["productName"])
}
default:
t.Errorf("Unexpected test data for edition %s\n", s.edition)
}
// 'cloudPak*' annotations should _not_ be present if the entitlement is standalone
if s.pes == webspherelibertyv1.LicenseEntitlementStandalone {
if _, exists := pts.Annotations["productCloudpakRatio"]; exists {
t.Errorf("productCloudpakRatio should not exist but was %s\n", pts.Annotations["productCloudpakRatio"])
}
if _, exists := pts.Annotations["cloudpakName"]; exists {
t.Errorf("cloudpakName should not exist but was %s\n", pts.Annotations["cloudpakName"])
}
if _, exists := pts.Annotations["cloudpakId"]; exists {
t.Errorf("cloudpakId should not exist but was %s\n", pts.Annotations["cloudpakId"])
}
} else {
if !checkRatio(pts.Annotations["productCloudpakRatio"], s.edition) {
t.Errorf("Unexpected productCloudpakRatio %s for edition %s\n", pts.Annotations["productCloudpakRatio"], s.edition)
}
if !checkID(pts.Annotations["cloudpakId"], s.pes) {
t.Errorf("Unexpected cloudpakId %s for entitlement %s\n", pts.Annotations["cloudpakId"], s.pes)
}
if !checkName(pts.Annotations["cloudpakName"], s.pes) {
t.Errorf("Unexpected cloudpakName %s for entitlement %s\n", pts.Annotations["cloudpakName"], s.pes)
}
}

}

}

func checkRatio(ratio string, edition webspherelibertyv1.LicenseEdition) bool {
if ratio == "4:1" && edition == webspherelibertyv1.LicenseEditionBase {
return true
}
if ratio == "8:1" && edition == webspherelibertyv1.LicenseEditionCore {
return true
}
if ratio == "1:1" && edition == webspherelibertyv1.LicenseEditionND {
return true
}
return false
}
func checkID(id string, pes webspherelibertyv1.LicenseEntitlement) bool {
if id == "4df52d2cdc374ba09f631a650ad2b5bf" && pes == webspherelibertyv1.LicenseEntitlementCP4Apps {
return true
}
if id == "be8ae84b3dd04d81b90af0d846849182" && pes == webspherelibertyv1.LicenseEntitlementFamilyEdition {
return true
}
if id == "6358611af04743f99f42dadcd6e39d52" && pes == webspherelibertyv1.LicenseEntitlementWSHE {
return true
}
return false
}
func checkName(name string, pes webspherelibertyv1.LicenseEntitlement) bool {
if name == string(pes) {
return true
}
return false
}

// Helper Functions
func envSliceToMap(env []corev1.EnvVar, data map[string][]byte, t *testing.T) map[string]string {
out := map[string]string{}
Expand Down

0 comments on commit f039f6f

Please sign in to comment.