github.com/ablease/cli@v6.37.1-0.20180613014814-3adbb7d7fb19+incompatible/actor/v2action/service_instance_summary.go (about)

     1  package v2action
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant"
     9  	"code.cloudfoundry.org/cli/util/sorting"
    10  	log "github.com/sirupsen/logrus"
    11  )
    12  
    13  type ServiceInstanceShareType string
    14  
    15  const (
    16  	ServiceInstanceIsSharedFrom ServiceInstanceShareType = "SharedFrom"
    17  	ServiceInstanceIsSharedTo   ServiceInstanceShareType = "SharedTo"
    18  	ServiceInstanceIsNotShared  ServiceInstanceShareType = "NotShared"
    19  )
    20  
    21  type ServiceInstanceSummary struct {
    22  	ServiceInstance
    23  
    24  	ServicePlan                       ServicePlan
    25  	Service                           Service
    26  	ServiceInstanceSharingFeatureFlag bool
    27  	ServiceInstanceShareType          ServiceInstanceShareType
    28  	ServiceInstanceSharedFrom         ServiceInstanceSharedFrom
    29  	ServiceInstanceSharedTos          []ServiceInstanceSharedTo
    30  	BoundApplications                 []BoundApplication
    31  }
    32  
    33  func (s ServiceInstanceSummary) IsShareable() bool {
    34  	return s.ServiceInstanceSharingFeatureFlag && s.Service.Extra.Shareable
    35  }
    36  
    37  func (s ServiceInstanceSummary) IsNotShared() bool {
    38  	return s.ServiceInstanceShareType == ServiceInstanceIsNotShared
    39  }
    40  
    41  func (s ServiceInstanceSummary) IsSharedFrom() bool {
    42  	return s.ServiceInstanceShareType == ServiceInstanceIsSharedFrom
    43  }
    44  
    45  func (s ServiceInstanceSummary) IsSharedTo() bool {
    46  	return s.ServiceInstanceShareType == ServiceInstanceIsSharedTo
    47  }
    48  
    49  type BoundApplication struct {
    50  	AppName            string
    51  	ServiceBindingName string
    52  }
    53  
    54  func (actor Actor) GetServiceInstanceSummaryByNameAndSpace(name string, spaceGUID string) (ServiceInstanceSummary, Warnings, error) {
    55  	serviceInstance, instanceWarnings, err := actor.GetServiceInstanceByNameAndSpace(name, spaceGUID)
    56  	allWarnings := Warnings(instanceWarnings)
    57  	if err != nil {
    58  		return ServiceInstanceSummary{}, allWarnings, err
    59  	}
    60  
    61  	serviceInstanceSummary, warnings, err := actor.getSummaryInfoCompositeForInstance(spaceGUID, serviceInstance, true)
    62  	return serviceInstanceSummary, append(allWarnings, warnings...), err
    63  }
    64  
    65  func (actor Actor) GetServiceInstancesSummaryBySpace(spaceGUID string) ([]ServiceInstanceSummary, Warnings, error) {
    66  	serviceInstances, warnings, err := actor.CloudControllerClient.GetSpaceServiceInstances(
    67  		spaceGUID,
    68  		true)
    69  	allWarnings := Warnings(warnings)
    70  
    71  	log.WithField("number_of_service_instances", len(serviceInstances)).Info("listing number of service instances")
    72  
    73  	var summaryInstances []ServiceInstanceSummary
    74  	for _, instance := range serviceInstances {
    75  		serviceInstanceSummary, summaryInfoWarnings, summaryInfoErr := actor.getSummaryInfoCompositeForInstance(
    76  			spaceGUID,
    77  			ServiceInstance(instance),
    78  			false)
    79  		allWarnings = append(allWarnings, summaryInfoWarnings...)
    80  		if summaryInfoErr != nil {
    81  			return nil, allWarnings, summaryInfoErr
    82  		}
    83  		summaryInstances = append(summaryInstances, serviceInstanceSummary)
    84  	}
    85  
    86  	sort.Slice(summaryInstances, func(i, j int) bool {
    87  		return sorting.LessIgnoreCase(summaryInstances[i].Name, summaryInstances[j].Name)
    88  	})
    89  
    90  	return summaryInstances, allWarnings, err
    91  }
    92  
    93  // getAndSetSharedInformation gets a service instance's shared from or shared to information,
    94  func (actor Actor) getAndSetSharedInformation(summary *ServiceInstanceSummary, spaceGUID string) (Warnings, error) {
    95  	var (
    96  		warnings Warnings
    97  		err      error
    98  	)
    99  
   100  	// Part of determining if a service instance is shareable, we need to find
   101  	// out if the service_instance_sharing feature flag is enabled
   102  	featureFlags, featureFlagsWarnings, featureFlagsErr := actor.CloudControllerClient.GetConfigFeatureFlags()
   103  	allWarnings := Warnings(featureFlagsWarnings)
   104  	if featureFlagsErr != nil {
   105  		return allWarnings, featureFlagsErr
   106  	}
   107  
   108  	for _, flag := range featureFlags {
   109  		if flag.Name == string(constant.FeatureFlagServiceInstanceSharing) {
   110  			summary.ServiceInstanceSharingFeatureFlag = flag.Enabled
   111  		}
   112  	}
   113  
   114  	// Service instance is shared from if:
   115  	// 1. the source space of the service instance is empty (API returns json null)
   116  	// 2. the targeted space is not the same as the source space of the service instance AND
   117  	//    we call the shared_from url and it returns a non-empty resource
   118  	if summary.ServiceInstance.SpaceGUID == "" || summary.ServiceInstance.SpaceGUID != spaceGUID {
   119  		summary.ServiceInstanceSharedFrom, warnings, err = actor.GetServiceInstanceSharedFromByServiceInstance(summary.ServiceInstance.GUID)
   120  		allWarnings = append(allWarnings, warnings...)
   121  		if err != nil {
   122  			// if the API version does not support service instance sharing, ignore the 404
   123  			if _, ok := err.(ccerror.ResourceNotFoundError); !ok {
   124  				return allWarnings, err
   125  			}
   126  		}
   127  
   128  		if summary.ServiceInstanceSharedFrom.SpaceGUID != "" {
   129  			summary.ServiceInstanceShareType = ServiceInstanceIsSharedFrom
   130  		} else {
   131  			summary.ServiceInstanceShareType = ServiceInstanceIsNotShared
   132  		}
   133  
   134  		return allWarnings, nil
   135  	}
   136  
   137  	// Service instance is shared to if:
   138  	// the targeted space is the same as the source space of the service instance AND
   139  	// we call the shared_to url and get a non-empty list
   140  	summary.ServiceInstanceSharedTos, warnings, err = actor.GetServiceInstanceSharedTosByServiceInstance(summary.ServiceInstance.GUID)
   141  	allWarnings = append(allWarnings, warnings...)
   142  	if err != nil {
   143  		// if the API version does not support service instance sharing, ignore the 404
   144  		if _, ok := err.(ccerror.ResourceNotFoundError); !ok {
   145  			return allWarnings, err
   146  		}
   147  	}
   148  
   149  	if len(summary.ServiceInstanceSharedTos) > 0 {
   150  		summary.ServiceInstanceShareType = ServiceInstanceIsSharedTo
   151  	} else {
   152  		summary.ServiceInstanceShareType = ServiceInstanceIsNotShared
   153  	}
   154  
   155  	return allWarnings, nil
   156  }
   157  
   158  func (actor Actor) getSummaryInfoCompositeForInstance(spaceGUID string, serviceInstance ServiceInstance, retrieveSharedInfo bool) (ServiceInstanceSummary, Warnings, error) {
   159  	log.WithField("GUID", serviceInstance.GUID).Info("looking up service instance info")
   160  
   161  	serviceInstanceSummary := ServiceInstanceSummary{ServiceInstance: serviceInstance}
   162  	var (
   163  		serviceBindings []ServiceBinding
   164  		allWarnings     Warnings
   165  	)
   166  
   167  	if serviceInstance.IsManaged() {
   168  		log.Debug("service is managed")
   169  		if retrieveSharedInfo {
   170  			sharedWarnings, err := actor.getAndSetSharedInformation(&serviceInstanceSummary, spaceGUID)
   171  			allWarnings = Warnings(sharedWarnings)
   172  			if err != nil {
   173  				log.WithField("GUID", serviceInstance.GUID).Errorln("looking up share info:", err)
   174  				return serviceInstanceSummary, allWarnings, err
   175  			}
   176  		}
   177  
   178  		servicePlan, planWarnings, err := actor.GetServicePlan(serviceInstance.ServicePlanGUID)
   179  		allWarnings = append(allWarnings, planWarnings...)
   180  		if err != nil {
   181  			log.WithField("service_plan_guid", serviceInstance.ServicePlanGUID).Errorln("looking up service plan:", err)
   182  			if _, ok := err.(ccerror.ForbiddenError); !ok {
   183  				return serviceInstanceSummary, allWarnings, err
   184  			}
   185  			log.Warning("Forbidden Error - ignoring and continue")
   186  			allWarnings = append(allWarnings, fmt.Sprintf("This org is not authorized to view necessary data about this service plan. Contact your administrator regarding service GUID %s.", serviceInstance.ServicePlanGUID))
   187  		}
   188  		serviceInstanceSummary.ServicePlan = servicePlan
   189  
   190  		service, serviceWarnings, err := actor.GetService(serviceInstance.ServiceGUID)
   191  		allWarnings = append(allWarnings, serviceWarnings...)
   192  		if err != nil {
   193  			log.WithField("service_guid", serviceInstance.ServiceGUID).Errorln("looking up service:", err)
   194  			if _, ok := err.(ccerror.ForbiddenError); !ok {
   195  				return serviceInstanceSummary, allWarnings, err
   196  			}
   197  			log.Warning("Forbidden Error - ignoring and continue")
   198  			allWarnings = append(allWarnings, fmt.Sprintf("This org is not authorized to view necessary data about this service. Contact your administrator regarding service GUID %s.", serviceInstance.ServiceGUID))
   199  		}
   200  		serviceInstanceSummary.Service = service
   201  
   202  		var bindingsWarnings Warnings
   203  		serviceBindings, bindingsWarnings, err = actor.GetServiceBindingsByServiceInstance(serviceInstance.GUID)
   204  		allWarnings = append(allWarnings, bindingsWarnings...)
   205  		if err != nil {
   206  			log.WithField("GUID", serviceInstance.GUID).Errorln("looking up service binding:", err)
   207  			return serviceInstanceSummary, allWarnings, err
   208  		}
   209  	} else {
   210  		log.Debug("service is user provided")
   211  		var bindingsWarnings Warnings
   212  		var err error
   213  		serviceBindings, bindingsWarnings, err = actor.GetServiceBindingsByUserProvidedServiceInstance(serviceInstance.GUID)
   214  		allWarnings = append(allWarnings, bindingsWarnings...)
   215  		if err != nil {
   216  			log.WithField("service_instance_guid", serviceInstance.GUID).Errorln("looking up service bindings:", err)
   217  			return serviceInstanceSummary, allWarnings, err
   218  		}
   219  	}
   220  
   221  	for _, serviceBinding := range serviceBindings {
   222  		log.WithFields(log.Fields{
   223  			"app_guid":             serviceBinding.AppGUID,
   224  			"service_binding_guid": serviceBinding.GUID,
   225  		}).Debug("application lookup")
   226  
   227  		app, appWarnings, err := actor.GetApplication(serviceBinding.AppGUID)
   228  		allWarnings = append(allWarnings, appWarnings...)
   229  		if err != nil {
   230  			log.WithFields(log.Fields{
   231  				"app_guid":             serviceBinding.AppGUID,
   232  				"service_binding_guid": serviceBinding.GUID,
   233  			}).Errorln("looking up application:", err)
   234  			return serviceInstanceSummary, allWarnings, err
   235  		}
   236  
   237  		serviceInstanceSummary.BoundApplications = append(serviceInstanceSummary.BoundApplications, BoundApplication{AppName: app.Name, ServiceBindingName: serviceBinding.Name})
   238  	}
   239  
   240  	sort.Slice(
   241  		serviceInstanceSummary.BoundApplications,
   242  		func(i, j int) bool {
   243  			return sorting.LessIgnoreCase(serviceInstanceSummary.BoundApplications[i].AppName, serviceInstanceSummary.BoundApplications[j].AppName)
   244  		})
   245  
   246  	return serviceInstanceSummary, allWarnings, nil
   247  }