Skip to content

Commit

Permalink
APIGOV-28984 [SDK] Custom unit configuration and client code
Browse files Browse the repository at this point in the history
  • Loading branch information
Deepak Kasu committed Oct 16, 2024
1 parent 5d14643 commit 42f7c46
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 16 deletions.
18 changes: 18 additions & 0 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
"github.com/Axway/agent-sdk/pkg/util"
hc "github.com/Axway/agent-sdk/pkg/util/healthcheck"
"github.com/Axway/agent-sdk/pkg/util/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

// AgentStatus - status for Agent resource
Expand Down Expand Up @@ -164,7 +166,23 @@ func InitializeWithAgentFeatures(centralCfg config.CentralConfig, agentFeaturesC
return err
}
}
// call the metric services.
metricServicesConfigs := agentFeaturesCfg.GetMetricServicesConfigs()
// iterate over each metric service config
for _, config := range metricServicesConfigs {
ctx := context.WithValue(context.Background(), ctxLogger, logger)
// Initialize custom units client
c := &customunit.customUnitMetricReportingClient{

Check failure on line 175 in pkg/agent/agent.go

View workflow job for this annotation

GitHub Actions / test

undefined: customunit
ctx: ctx,
url: config.GetMetricServiceURL(),
dialOpts: []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
},
}

c.MetricReporting()

}
if !agent.isInitialized {
err = handleInitialization()
if err != nil {
Expand Down
133 changes: 124 additions & 9 deletions pkg/agent/handler/accessrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ import (
"fmt"

agentcache "github.com/Axway/agent-sdk/pkg/agent/cache"
"github.com/Axway/agent-sdk/pkg/amplify/agent/customunits"
apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
defs "github.com/Axway/agent-sdk/pkg/apic/definitions"
prov "github.com/Axway/agent-sdk/pkg/apic/provisioning"
"github.com/Axway/agent-sdk/pkg/config"
"github.com/Axway/agent-sdk/pkg/util"
"github.com/Axway/agent-sdk/pkg/util/log"
"github.com/Axway/agent-sdk/pkg/watchmanager/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

const (
Expand All @@ -26,19 +31,21 @@ type arProvisioner interface {

type accessRequestHandler struct {
marketplaceHandler
prov arProvisioner
cache agentcache.Manager
client client
encryptSchema encryptSchemaFunc
prov arProvisioner
cache agentcache.Manager
client client
encryptSchema encryptSchemaFunc
metricServicesConfig []config.MetricServiceConfiguration
}

// NewAccessRequestHandler creates a Handler for Access Requests
func NewAccessRequestHandler(prov arProvisioner, cache agentcache.Manager, client client) Handler {
func NewAccessRequestHandler(prov arProvisioner, cache agentcache.Manager, client client, metricSvcCfg []config.MetricServiceConfiguration) Handler {
return &accessRequestHandler{
prov: prov,
cache: cache,
client: client,
encryptSchema: encryptSchema,
prov: prov,
cache: cache,
client: client,
encryptSchema: encryptSchema,
metricServicesConfig: metricSvcCfg,
}
}

Expand Down Expand Up @@ -133,6 +140,57 @@ func (h *accessRequestHandler) onPending(ctx context.Context, ar *management.Acc
data := map[string]interface{}{}
status, accessData := h.prov.AccessRequestProvision(req)

if status.GetStatus() == prov.Success {
metricServicesConfigs := h.metricServicesConfig
errorQE := false
errMessage := ""
// Build quota info
quotaInfo, err := h.buildQuotaInfo(ctx, ar)
if err != nil {
log.WithError(err).Errorf("error building quota info")
h.onError(ctx, ar, err)
return ar
}
// iterate over each metric service config
for _, config := range metricServicesConfigs {

if config.MetricServiceEnabled() {
// Initialize custom units client
c := &CustomUnitsQEClient{
logger: getLoggerFromContext(ctx),
ctx: ctx,
quotaInfo: quotaInfo,
url: config.GetMetricServiceURL(),
dialOpts: []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
},
}

response, err := c.GetQuotaEnforcementInfo()

// if error from QE and reject on fail, we return the error back to the central
if err != nil && config.RejectOnFailEnabled() {
errorQE = true
errMessage = errMessage + fmt.Sprintf("TODO: message: %s", err.Error())
}
if response.GetError() != "" {
status = prov.NewRequestStatusBuilder().
//TODO: set the correct status message. ALSO confirm if needs to set to "SUCCESS" ????
SetMessage(fmt.Sprintf("TODO: message: ")).
SetCurrentStatusReasons(ar.Status.Reasons).
Success()
}
}
}

if errorQE {
status = prov.NewRequestStatusBuilder().
SetMessage(errMessage).
SetCurrentStatusReasons(ar.Status.Reasons).
Failed()
}
}

if status.GetStatus() == prov.Success && accessData != nil {
sec := app.Spec.Security
d := accessData.GetData()
Expand Down Expand Up @@ -260,6 +318,41 @@ func (h *accessRequestHandler) getARD(ctx context.Context, ar *management.Access
return ard, err
}

func (h *accessRequestHandler) buildQuotaInfo(ctx context.Context, ar *management.AccessRequest) (*customunits.QuotaInfo, error) {
// Get service instance from access request to fetch the api service
instance, err := h.getServiceInstance(ctx, ar)
if err != nil {
return nil, err
}
serviceRef := instance.GetReferenceByGVK(management.APIServiceGVK())
serviceID := serviceRef.ID
service := h.cache.GetAPIServiceWithAPIID(serviceID)
extAPIID, err := util.GetAgentDetailsValue(service, defs.AttrExternalAPIID)
if err != nil {
return nil, err
}
// Get app info from the access request
appRef := instance.GetReferenceByGVK(management.ManagedApplicationGVK())
appName := appRef.Name
app := h.cache.GetManagedApplicationByName(appName)

q := &customunits.QuotaInfo{
ApiInfo: &customunits.APIInfo{
ServiceDetails: util.GetAgentDetailStrings(service),
ServiceName: service.Name,
ServiceID: serviceID,
ExternalAPIID: extAPIID,
},
AppInfo: &customunits.AppInfo{
AppDetails: util.GetAgentDetailStrings(app),
AppName: app.Name,
AppID: app.Metadata.ID,
},
}

return q, nil
}

func (h *accessRequestHandler) getServiceInstance(_ context.Context, ar *management.AccessRequest) (*apiv1.ResourceInstance, error) {
instRef := ar.GetReferenceByGVK(management.APIServiceInstanceGVK())
instID := instRef.ID
Expand Down Expand Up @@ -349,3 +442,25 @@ func (r provAccReq) GetInstanceDetails() map[string]interface{} {
func (r provAccReq) GetQuota() prov.Quota {
return r.quota
}

type CustomUnitsQEClient struct {
ctx context.Context
quotaInfo *customunits.QuotaInfo
logger log.FieldLogger
dialOpts []grpc.DialOption
cOpts []grpc.CallOption
url string
conn *grpc.ClientConn
}

func (c *CustomUnitsQEClient) GetQuotaEnforcementInfo() (*customunits.QuotaEnforcementResponse, error) {
conn, err := grpc.DialContext(c.ctx, c.url, c.dialOpts...)
if err != nil {
return nil, err
}
quotaEnforcementClient := customunits.NewQuotaEnforcementClient(conn)

response, err := quotaEnforcementClient.QuotaEnforcementInfo(c.ctx, c.quotaInfo, c.cOpts...)

return response, err
}
2 changes: 1 addition & 1 deletion pkg/agent/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ func RegisterProvisioner(provisioner provisioning.Provisioning) {
if agent.cfg.GetAgentType() == config.DiscoveryAgent || agent.cfg.GetAgentType() == config.GovernanceAgent {
agent.proxyResourceHandler.RegisterTargetHandler(
"accessrequesthandler",
handler.NewAccessRequestHandler(agent.provisioner, agent.cacheManager, agent.apicClient),
handler.NewAccessRequestHandler(agent.provisioner, agent.cacheManager, agent.apicClient, agent.agentFeaturesCfg.GetMetricServicesConfigs()),
)
agent.proxyResourceHandler.RegisterTargetHandler(
"managedappHandler",
Expand Down
19 changes: 13 additions & 6 deletions pkg/config/agentfeaturesconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ type AgentFeaturesConfig interface {
GetExternalIDPConfig() ExternalIDPConfig
AgentStatusUpdatesEnabled() bool
SetPersistentCache(enable bool)
GetMetricServicesConfigs() []MetricServiceConfiguration
}

// AgentFeaturesConfiguration - Structure to hold the agent features config
type AgentFeaturesConfiguration struct {
AgentFeaturesConfig
IConfigValidator
ConnectToCentral bool `config:"connectToCentral"`
ProcessSystemSignals bool `config:"processSystemSignals"`
VersionChecker bool `config:"versionChecker"`
PersistCache bool `config:"persistCache"`
ExternalIDPConfig ExternalIDPConfig `config:"idp"`
AgentStatusUpdates bool `config:"agentStatusUpdates"`
ConnectToCentral bool `config:"connectToCentral"`
ProcessSystemSignals bool `config:"processSystemSignals"`
VersionChecker bool `config:"versionChecker"`
PersistCache bool `config:"persistCache"`
ExternalIDPConfig ExternalIDPConfig `config:"idp"`
AgentStatusUpdates bool `config:"agentStatusUpdates"`
MetricServicesConfigs []MetricServiceConfiguration `config:"metricServices"`
}

// NewAgentFeaturesConfiguration - Creates the default agent features config
Expand Down Expand Up @@ -67,6 +69,11 @@ func (c *AgentFeaturesConfiguration) GetExternalIDPConfig() ExternalIDPConfig {
return c.ExternalIDPConfig
}

// GetMetricServicesConfigs - returns the configs for metric services
func (c *AgentFeaturesConfiguration) GetMetricServicesConfigs() []MetricServiceConfiguration {
return c.MetricServicesConfigs
}

// AgentStatusUpdatesEnabled - True if the agent SDK should manage the status update.
func (c *AgentFeaturesConfiguration) AgentStatusUpdatesEnabled() bool {
return c.AgentStatusUpdates
Expand Down
49 changes: 49 additions & 0 deletions pkg/config/metricserviceconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package config

import (
"net/url"

"github.com/Axway/agent-sdk/pkg/util/exception"
)

const (
pathMetricServiceEnable = "agentFeatures.metricServices.enable"
pathMetricServiceURL = "agentFeatures.metricServices.url"
pathRejectOnFail = "agentFeatures.metricServices.rejectOnFail"
)

type MetricServiceConfig interface {
MetricServiceEnabled() bool
GetMetricServiceURL() string
RejectOnFailEnabled() bool
validate()
}

type MetricServiceConfiguration struct {
MetricServiceConfig
Enable bool `config:"enable"` // set to true to have the sdk initiate the connection to the custom metric service
URL string `config:"url"` // set the url that the agent will connect to the metric service on
RejectOnFail bool `config:"rejectOnFail"` // set to true to reject the access request if the quota enforcement call fails
}

func (a *MetricServiceConfiguration) validate() {
if a.GetMetricServiceURL() == "" {
exception.Throw(ErrBadConfig.FormatError(pathMetricServiceEnable))
} else if _, err := url.ParseRequestURI(a.GetMetricServiceURL()); err != nil {
exception.Throw(ErrBadConfig.FormatError(pathMetricServiceEnable))
}
}

func (c *MetricServiceConfiguration) MetricServiceEnabled() bool {
return c.Enable
}

// ProcessSystemSignalsEnabled - True if the agent SDK listens for system signals and manages shutdown
func (c *MetricServiceConfiguration) GetMetricServiceURL() string {
return c.URL
}

// VersionCheckerEnabled - True if the agent SDK should check for newer versions of the agent.
func (c *MetricServiceConfiguration) RejectOnFailEnabled() bool {
return c.RejectOnFail
}
Loading

0 comments on commit 42f7c46

Please sign in to comment.