Skip to content

Commit

Permalink
Sample application for sending a test report
Browse files Browse the repository at this point in the history
  • Loading branch information
huyhg committed Jan 16, 2020
1 parent dc7a2a6 commit 5267a29
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 112 deletions.
214 changes: 214 additions & 0 deletions entitlement.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package main

//
// Installation instruction (golang tools are required):
// $ make setup
// $ make deps
// $ make build
//
// Sample command:
// $ bin/ubbagent -logtostderr \
// -reporting-secret fake_reporting_secret.yaml \
// -service-name your-solution.your-service-id.appspot.com
// -metric-name your-metric-name \
// -metric-int-value 1
//
// The service name and metric name are configured when billing
// is setup for your project.
//
// If you deploy Cloud Bees Core Billable solution from Marketplace
// and obtain its reporting secret (look for *-reporting-secret Secret
// in the target namespace), you can use the following:
// $ bin/ubbagent -logtostderr \
// -reporting-secret reporting_secret.yaml \
// -service-name cloudbees-core-billable.mp-cloudbees.appspot.com \
// -metric-name user \
// -metric-int-value 1
//

import (
"context"
"encoding/base64"
"errors"
"flag"
"fmt"
"io/ioutil"
"os"
"time"

"github.com/GoogleCloudPlatform/ubbagent/config"
"golang.org/x/oauth2/google"
"google.golang.org/api/servicecontrol/v1"

"github.com/ghodss/yaml"
"github.com/golang/glog"
"github.com/google/uuid"
)

var secretPath = flag.String("reporting-secret", "", "K8s reporting secret YAML")
var serviceName = flag.String("service-name", "", "Service name")
var metricName = flag.String("metric-name", "", "Metric name")
var metricValue = flag.Int64("metric-int-value", 1, "Metric int64 value")

type secret struct {
Data secretData `json:"data"`
}

type secretData struct {
ConsumerID consumerID `json:"consumer-id"`
EntitlementID entitlementID `json:"entitlement-id"`
ReportingKey reportingKey `json:"reporting-key"`
}

type consumerID string

func (c *consumerID) UnmarshalJSON(data []byte) error {
if c == nil {
return errors.New("EncodedServiceAccountKey.UnmarshalJSON: nil pointer")
}
decoded, err := decodeBase64Encoded(data)
if err != nil {
return err
}
*c = consumerID(decoded)
return nil
}

type entitlementID string

func (c *entitlementID) UnmarshalJSON(data []byte) error {
if c == nil {
return errors.New("EncodedServiceAccountKey.UnmarshalJSON: nil pointer")
}
decoded, err := decodeBase64Encoded(data)
if err != nil {
return err
}
*c = entitlementID(decoded)
return nil
}

type reportingKey config.EncodedServiceAccountKey

func (c *reportingKey) UnmarshalJSON(data []byte) error {
if c == nil {
return errors.New("EncodedServiceAccountKey.UnmarshalJSON: nil pointer")
}
decoded, err := decodeBase64Encoded(data)
if err != nil {
return err
}
if decoded == nil {
return err
}
accountKey := config.EncodedServiceAccountKey{}
accountKey.UnmarshalJSON(decoded)
*c = reportingKey(accountKey)
return nil
}

func decodeBase64Encoded(data []byte) ([]byte, error) {
var decoded []byte
var encodedStr string

// First we decode the data into a string to get rid of any start and end quotes.
err := yaml.Unmarshal(data, &encodedStr)
if err != nil {
return nil, errors.New("EncodedServiceAccountKey.UnmarshalJSON: not a string value")
}

decoded, err = base64.StdEncoding.DecodeString(encodedStr)
if err != nil {
return nil, errors.New("EncodedServiceAccountKey.UnmarshalJSON: not a valid base64 value")
}

return decoded, nil
}

func main() {
flag.Parse()

if *secretPath == "" || *serviceName == "" || *metricName == "" {
fmt.Fprintln(os.Stderr, "Required flags must be specified")
flag.Usage()
os.Exit(2)
}
reportingSecret, err := load(*secretPath)
check(err)
glog.Infof("ReportingSecret=%+v", reportingSecret)
service, err := newServiceControl(reportingSecret.Data.ReportingKey)
check(err)

opID, err := uuid.NewRandom()
check(err)
op := &servicecontrol.Operation{
OperationId: opID.String(),
// ServiceControl requires this field but doesn't indicate what it's supposed to be.
OperationName: fmt.Sprintf("%v/report", *serviceName),
StartTime: time.Now().Format(time.RFC3339Nano),
EndTime: time.Now().Format(time.RFC3339Nano),
ConsumerId: string(reportingSecret.Data.ConsumerID),
MetricValueSets: []*servicecontrol.MetricValueSet{
{
MetricName: fmt.Sprintf("%v/%v", *serviceName, *metricName),
MetricValues: []*servicecontrol.MetricValue{
&servicecontrol.MetricValue{
StartTime: time.Now().Format(time.RFC3339Nano),
EndTime: time.Now().Format(time.RFC3339Nano),
Int64Value: &[]int64{*metricValue}[0],
},
},
},
},
}
req := &servicecontrol.ReportRequest{
Operations: []*servicecontrol.Operation{op},
}
response, err := service.Services.Report(*serviceName, req).Do()
glog.Infof("Response=%v\nError=%v", response, err)
if err == nil {
glog.Infof("SUCCESS!!!")
} else {
glog.Fatalf("DID NOT SUCCEED")
}
}

func check(err error) {
if err != nil {
glog.Fatalf("Error: %v", err)
}
}

func newServiceControl(jsonKey []byte) (*servicecontrol.Service, error) {
config, err := google.JWTConfigFromJSON(jsonKey, servicecontrol.ServicecontrolScope)
if err != nil {
return nil, err
}
client := config.Client(context.Background())
client.Timeout = 30 * time.Second
service, err := servicecontrol.New(client)
if err != nil {
return nil, err
}
return service, nil
}

func load(path string) (*secret, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
secret, err := parse(data)
if err != nil {
return nil, err
}
return secret, nil
}

func parse(data []byte) (*secret, error) {
c := &secret{}
if err := yaml.Unmarshal(data, c); err != nil {
return nil, err
}
return c, nil
}
7 changes: 7 additions & 0 deletions fake_reporting_secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
data:
consumer-id: cHJvamVjdDpwci14eHh4LWZha2UteHh4eA==
entitlement-id: ZmZmZmZmZmYtZmZmZi1mZmZmLWZmZmYtZmZmZmZmZmZmZmZm
reporting-key: ZXdvZ0lDSjBlWEJsSWpvZ0luTmxjblpwWTJWZllXTmpiM1Z1ZENJc0NpQWdJbkJ5YjJwbFkzUmZhV1FpT2lBaVkyeHZkV1F0YldGeWEyVjBjR3hoWTJVdGRHOXZiSE1pTEFvZ0lDSndjbWwyWVhSbFgydGxlVjlwWkNJNklDSm1OR1ppTUdRMk16TmhaRFEzWWpFd1pUSmhORFJqTTJaak1HWmlZakEzTlRrNE56Z3lZMkpqSWl3S0lDQWljSEpwZG1GMFpWOXJaWGtpT2lBaUxTMHRMUzFDUlVkSlRpQlFVa2xXUVZSRklFdEZXUzB0TFMwdFhHNU5TVWxGZGtGSlFrRkVRVTVDWjJ0eGFHdHBSemwzTUVKQlVVVkdRVUZUUTBKTFdYZG5aMU5wUVdkRlFVRnZTVUpCVVVONk1HOWlWbXh0VmpBNE1GVm9YRzV1WTNoMGQyZHlUVTFKTm1kMEsyTmhObFJxZGs0dmJrNW5hREZ1ZGsxVU1YUjBObnB0WWpaQ01HSTBTazF2V0V4SE4ycGpMM0Y1T1dKTGEwdERPRkEyWEc1bFdESmpXbkExWkVoT1VsQkZVRXhVWXpGV1RuQldZM0JQTm1ReFVYUnNWbTlOWVdVelZtTXlNbEYzTXpCQ2FsTkhTMU12V0U5V2IyUnNUeXRRTHpZM1hHNXhNMUZhVDNwWmJqRTRNakEyT0ZkM0wwVmxUM0UzWW1GdlQzQmllVlJEUlZRMlJUY3JPRzhyYVUxRVQxSklaVzVyTVRSck1rWjZSMjR6SzJOcU9VWklYRzVUTkhGQ0wxZFNLelF4Wm01bE5XOTFOVTVKU1hFMGFXVllWV2RsTnpaNk9GWXhaRE4xZFdGNWNGaGhZME50VEN0TVpGVnlZWFkxYjBSSU4zbEVTVUo2WEc1TWFHRkdTMjlsU0dKNlJGcFRkR2RTYVVKcFZqWkZielpoVFd4dU4wTndUR3hxYlZOUGRHb3JiVk5TYkhZemRFVTJibFU1TjFacU9FcHRhV05DUTNwV1hHNUpkRGx1TkhSelNFRm5UVUpCUVVWRFoyZEZRVUpTYm5Gd05rbHdlRVpKVW5WMFNUbEJUMWxhWlZaRldDOVhUMHRNYkZSQ2RpdFBUR1JvTWtRdmJEWk9YRzVaU1VwemRXVnhXbVJ6VWxVNVducFdlbE5sTDBGaFNIZHJOQzlEZGtsblRqWm5kakZSTTBWVU1FRlRPVXg1UW1Ka1l6QnlPVk53ZG1KdFZHRkJUWEJ6WEc1b2ExaFhaMlpQVUV4R1MyMDVWRGhMTTFSaWRYZFpXbFJUWW1sR2JsWkhUa2R3VkZOMmJqVXJjMFV5Y1dOU1dEVk1aV0Z1YkVaeE0wTkNTbXhxYTFOc1hHNWFZMDhyVW5ORVVqUlFOREJGVVdVd2FXUXhhek5UWVc5Sk1IUkJTMHRhTkdOQ2JHUmhTMUpCVkZSWE5IQnpOa2R2U0c5eU9WSTJOREJZWTFaUlN6bFdYRzVsVGxKUGFtTXdUbWx0Um5sS1VXWlVTMk5YYVV4SU1WaGlRVFJVUTI5R1YwaE9kVU5sTDJoV1VWUlNWbkpTT1hWb01YVlVTbkI1VUc0MFFrTXpabnBTWEc1TmRIRnlOWGxoVEc1eWJUTXlZMFFyYjBZclZuWllOMUpsVm10TVpuWk1TazVEVlVSVE9FRjFjVkZMUW1kUlJEQTROMlJIVUZKaFRXSkdPVVY1Ym1WcVhHNDVTM1JxU2xOQmNsaHpZbUp3YmxKUVJ6bFNhMEZVU1RsR2FYQnRURnBhY3pSVGFEYzVPV2RZTlZkUE5YUlZObGRCWVZWcVRVUjFNM3B6VEdaQ05DdFBYRzVOTkU5TVFtbDBMM2t3VnpGQlpsTTBUVVkyVG1wbWNFbGFTVWxzT1drMVowSkxVbkJGUVhCMGRtVnRTVzlHWkZsUlkweFRiMkYwU0ZKbGNIQmxOMmxpWEc1aU1IRm5ZaTlVVm5ORllYaGhaMUIyS3poSU4zcEVjVVpYVVV0Q1oxRkROemR6TlVnMFVqTjFXRFJVUzNKUk9XVTBTVkZOTm05cVVFSXhRazlFV0cxalhHNXJlVEpDVUc1TGNsTkJiMWN5Y2xsWlJYcG5OWHBGUW1weWVuZHNPVTFuSzBsaFFYVnViUzl5ZEVORlowbzJTMlpLVlhkWVEzaFdjVFpqVjIxeVZIaENYRzVoUTJaSFRFb3phaTg1YWxoTlEydEhUMnRVWVVoVWRqbGxjSFV3YkM5MFp6TTVOa3hDU1V4TWFXaG5PVzk2VVZvemJIbHJhemRIT1hoWWNtRkViVzVuWEc1S1RFUTVhM05rTTFoM1MwSm5SV054TDBObVJFaGxZMFZ2V2xaaFFXWkxNelZ2WlhsNFMzSXhTMWNyZERaQlRVbEJaV2huVmtwc1l6bEZjV3h0YUhabFhHNVBlVmg0WkRJMVVqZHRlVXBYWlVSS1lqVktUM1JFYzA5TWNEUm5SWHA0YzJsU05TdFdNbk5WZDNoaU5VUTBTRzlST0VJMk4wdHVWakJrTlROeVZHVnRYRzVuWVVsdmVpczNZMmsxY0habk5VVllOR2xRVTFwMlNWcFNVMk5MYkVST1RUTllSRXAwYldaVWFFZGhUbVE0Um1zNGVFcFhXSFphV2tGdlIwRlpVRTA0WEc1U1dXRlVNakZKTldab2EzcFZZakl2VVdFMlNXSXdNRlpzTXpaTFJ6QlZkRGt6ZGxGNWFESTJNM0pzY25OU1dGSk1jbVkxUXpkUWREaHhURW96YjNWWlhHNVRRbE5EU201V2FHeFhXRGxHWkRZeU1YcG9ibXA1VlZWVGRqQmFiR0ZDTW5wR2VHVkJOalJOU0dzNFFrTjFOWEZqU2pobFVVcEVUVE5MYUM5RVUxaFJYRzVrTmxWWVIwbDFaMGc0VVdVM05qRjJNalZOTlRSWE1rMURRWFpvWjB4c1RTdFVUMDFhVkRoRFoxbENjalY1UjFwaU1sQkdaaXRLYldabVRVMUVORTU2WEc1bGJFcDFTMUpsWXpSaWVscHNORkJHUTFjM09IcEpNaTlEWlRaak9IUm5XR04wT0VwdFRVTTJSMmt4YUVSQ01TOHZabFpJU2pjeFJubFNZakJJWVhWUFhHNVRXSFoyVlhRMU9HRXZMMUJzYzFaVWJHTnVjR0oyVUVWUlJUWTBTalo2VWpsbkswUkxOV2hFT0dvNFVVeFZhRmhrZEhGWVlqVmhVWEE0UXpsek5HNVBYRzVpY1VSUVozVm9MMHRKYVZBMVdTdGhVRTlsYUc1M1BUMWNiaTB0TFMwdFJVNUVJRkJTU1ZaQlZFVWdTMFZaTFMwdExTMWNiaUlzQ2lBZ0ltTnNhV1Z1ZEY5bGJXRnBiQ0k2SUNKNGVIZ3RabUZyWlMxeVpYQnZjblJsY2kxNGVIaEFZMnh2ZFdRdGJXRnlhMlYwY0d4aFkyVXRkRzl2YkhNdWFXRnRMbWR6WlhKMmFXTmxZV05qYjNWdWRDNWpiMjBpTEFvZ0lDSmpiR2xsYm5SZmFXUWlPaUFpTVRBMU9EWXlNRE0zT0RRMU1qazVOekkzT0RJeklpd0tJQ0FpWVhWMGFGOTFjbWtpT2lBaWFIUjBjSE02THk5aFkyTnZkVzUwY3k1bmIyOW5iR1V1WTI5dEwyOHZiMkYxZEdneUwyRjFkR2dpTEFvZ0lDSjBiMnRsYmw5MWNta2lPaUFpYUhSMGNITTZMeTl2WVhWMGFESXVaMjl2WjJ4bFlYQnBjeTVqYjIwdmRHOXJaVzRpTEFvZ0lDSmhkWFJvWDNCeWIzWnBaR1Z5WDNnMU1EbGZZMlZ5ZEY5MWNtd2lPaUFpYUhSMGNITTZMeTkzZDNjdVoyOXZaMnhsWVhCcGN5NWpiMjB2YjJGMWRHZ3lMM1l4TDJObGNuUnpJaXdLSUNBaVkyeHBaVzUwWDNnMU1EbGZZMlZ5ZEY5MWNtd2lPaUFpYUhSMGNITTZMeTkzZDNjdVoyOXZaMnhsWVhCcGN5NWpiMjB2Y205aWIzUXZkakV2YldWMFlXUmhkR0V2ZURVd09TOTRlSGd0Wm1GclpTMXlaWEJ2Y25SbGNpMTRlSGdsTkRCamJHOTFaQzF0WVhKclpYUndiR0ZqWlMxMGIyOXNjeTVwWVcwdVozTmxjblpwWTJWaFkyTnZkVzUwTG1OdmJTSUtmUT09
kind: Secret
type: Opaque
112 changes: 0 additions & 112 deletions main.go

This file was deleted.

0 comments on commit 5267a29

Please sign in to comment.