github.com/Axway/agent-sdk@v1.1.101/pkg/agent/handler/managedapplication.go (about)

     1  package handler
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	agentcache "github.com/Axway/agent-sdk/pkg/agent/cache"
     8  	apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
     9  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    10  	defs "github.com/Axway/agent-sdk/pkg/apic/definitions"
    11  	prov "github.com/Axway/agent-sdk/pkg/apic/provisioning"
    12  	"github.com/Axway/agent-sdk/pkg/util"
    13  	"github.com/Axway/agent-sdk/pkg/watchmanager/proto"
    14  )
    15  
    16  const (
    17  	maFinalizer = "agent.managedapplication.provisioned"
    18  )
    19  
    20  type managedAppProvision interface {
    21  	ApplicationRequestProvision(applicationRequest prov.ApplicationRequest) (status prov.RequestStatus)
    22  	ApplicationRequestDeprovision(applicationRequest prov.ApplicationRequest) (status prov.RequestStatus)
    23  }
    24  
    25  type managedApplication struct {
    26  	marketplaceHandler
    27  	prov   managedAppProvision
    28  	cache  agentcache.Manager
    29  	client client
    30  }
    31  
    32  // NewManagedApplicationHandler creates a Handler for Credentials
    33  func NewManagedApplicationHandler(prov managedAppProvision, cache agentcache.Manager, client client) Handler {
    34  	return &managedApplication{
    35  		prov:   prov,
    36  		cache:  cache,
    37  		client: client,
    38  	}
    39  }
    40  
    41  // Handle processes grpc events triggered for ManagedApplications
    42  func (h *managedApplication) Handle(ctx context.Context, meta *proto.EventMeta, resource *apiv1.ResourceInstance) error {
    43  	action := GetActionFromContext(ctx)
    44  	if resource.Kind != management.ManagedApplicationGVK().Kind || h.prov == nil || h.shouldIgnoreSubResourceUpdate(action, meta) {
    45  		return nil
    46  	}
    47  
    48  	log := getLoggerFromContext(ctx).WithComponent("managedApplicationHandler")
    49  	ctx = setLoggerInContext(ctx, log)
    50  
    51  	app := &management.ManagedApplication{}
    52  	err := app.FromInstance(resource)
    53  	if err != nil {
    54  		log.WithError(err).Error("could not handle application request")
    55  		return nil
    56  	}
    57  
    58  	if ok := isStatusFound(app.Status); !ok {
    59  		log.Debug("could not handle application request as it did not have a status subresource")
    60  		return nil
    61  	}
    62  
    63  	ma := provManagedApp{
    64  		managedAppName: app.Name,
    65  		teamName:       h.getTeamName(ctx, app.Owner),
    66  		data:           util.GetAgentDetails(app),
    67  		consumerOrgID:  h.getConsumerOrgID(app),
    68  		id:             app.Metadata.ID,
    69  	}
    70  
    71  	if ok := h.shouldProcessPending(app.Status, app.Metadata.State); ok {
    72  		log.Trace("processing resource in pending status")
    73  		return h.onPending(ctx, app, ma)
    74  	}
    75  
    76  	if ok := h.shouldProcessDeleting(app.Status, app.Metadata.State, app.Finalizers); ok {
    77  		log.Trace("processing resource in deleting state")
    78  		h.onDeleting(ctx, app, ma)
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  func (h *managedApplication) onPending(ctx context.Context, app *management.ManagedApplication, pma provManagedApp) error {
    85  	log := getLoggerFromContext(ctx)
    86  	status := h.prov.ApplicationRequestProvision(pma)
    87  
    88  	app.Status = prov.NewStatusReason(status)
    89  
    90  	details := util.MergeMapStringString(util.GetAgentDetailStrings(app), status.GetProperties())
    91  	util.SetAgentDetails(app, util.MapStringStringToMapStringInterface(details))
    92  
    93  	// add finalizer
    94  	ri, _ := app.AsInstance()
    95  	if app.Status.Level == prov.Success.String() {
    96  		// only add finalizer on success
    97  		h.client.UpdateResourceFinalizer(ri, maFinalizer, "", true)
    98  	}
    99  
   100  	app.SubResources = map[string]interface{}{
   101  		defs.XAgentDetails: util.GetAgentDetails(app),
   102  	}
   103  
   104  	err := h.client.CreateSubResource(app.ResourceMeta, app.SubResources)
   105  	if err != nil {
   106  		log.WithError(err).Error("error creating subresources")
   107  	}
   108  
   109  	statusErr := h.client.CreateSubResource(app.ResourceMeta, map[string]interface{}{"status": app.Status})
   110  	if statusErr != nil {
   111  		log.WithError(statusErr).Error("error creating status subresources")
   112  		return statusErr
   113  	}
   114  
   115  	return err
   116  }
   117  
   118  func (h *managedApplication) onDeleting(ctx context.Context, app *management.ManagedApplication, pma provManagedApp) {
   119  	log := getLoggerFromContext(ctx)
   120  	status := h.prov.ApplicationRequestDeprovision(pma)
   121  
   122  	if status.GetStatus() == prov.Success {
   123  		ri, _ := app.AsInstance()
   124  		h.client.UpdateResourceFinalizer(ri, maFinalizer, "", false)
   125  	} else {
   126  		err := fmt.Errorf(status.GetMessage())
   127  		log.WithError(err).Error("request status was not Success, skipping")
   128  		h.onError(app, err)
   129  		h.client.CreateSubResource(app.ResourceMeta, app.SubResources)
   130  	}
   131  }
   132  
   133  // onError updates the managed app with an error status
   134  func (h *managedApplication) onError(ar *management.ManagedApplication, err error) {
   135  	ps := prov.NewRequestStatusBuilder()
   136  	status := ps.SetMessage(err.Error()).Failed()
   137  	ar.Status = prov.NewStatusReason(status)
   138  	ar.SubResources = map[string]interface{}{
   139  		"status": ar.Status,
   140  	}
   141  }
   142  
   143  func (h *managedApplication) getTeamName(_ context.Context, owner *apiv1.Owner) string {
   144  	teamName := ""
   145  	if owner != nil && owner.ID != "" {
   146  		team := h.cache.GetTeamByID(owner.ID)
   147  		if team != nil {
   148  			teamName = team.Name
   149  		}
   150  	}
   151  	return teamName
   152  }
   153  
   154  func (h *managedApplication) getConsumerOrgID(app *management.ManagedApplication) string {
   155  	consumerOrgID := ""
   156  	if app != nil && app.Marketplace.Resource.Owner != nil && app.Marketplace.Resource.Owner.Organization.ID != "" {
   157  		consumerOrgID = app.Marketplace.Resource.Owner.Organization.ID
   158  	}
   159  	return consumerOrgID
   160  }
   161  
   162  type provManagedApp struct {
   163  	managedAppName string
   164  	teamName       string
   165  	consumerOrgID  string
   166  	id             string
   167  	data           map[string]interface{}
   168  }
   169  
   170  // GetManagedApplicationName returns the name of the managed application
   171  func (a provManagedApp) GetManagedApplicationName() string {
   172  	return a.managedAppName
   173  }
   174  
   175  // GetTeamName gets the owning team name for the managed application
   176  func (a provManagedApp) GetID() string {
   177  	return a.id
   178  }
   179  
   180  // GetTeamName gets the owning team name for the managed application
   181  func (a provManagedApp) GetTeamName() string {
   182  	return a.teamName
   183  }
   184  
   185  // GetApplicationDetailsValue returns a value found on the managed application
   186  func (a provManagedApp) GetApplicationDetailsValue(key string) string {
   187  	if a.data == nil {
   188  		return ""
   189  	}
   190  
   191  	return util.ToString(a.data[key])
   192  }
   193  
   194  // GetConsumerOrgID returns the ID of the consumer org for the managed application
   195  func (a provManagedApp) GetConsumerOrgID() string {
   196  	return a.consumerOrgID
   197  }