github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/actor/cfnetworkingaction/policy.go (about)

     1  package cfnetworkingaction
     2  
     3  import (
     4  	"code.cloudfoundry.org/cfnetworking-cli-api/cfnetworking/cfnetv1"
     5  	"code.cloudfoundry.org/cli/actor/actionerror"
     6  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
     8  	"code.cloudfoundry.org/cli/resources"
     9  	"code.cloudfoundry.org/cli/util/batcher"
    10  	"code.cloudfoundry.org/cli/util/lookuptable"
    11  )
    12  
    13  type Policy struct {
    14  	SourceName           string
    15  	DestinationName      string
    16  	Protocol             string
    17  	DestinationSpaceName string
    18  	DestinationOrgName   string
    19  	StartPort            int
    20  	EndPort              int
    21  }
    22  
    23  func (actor Actor) AddNetworkPolicy(srcSpaceGUID, srcAppName, destSpaceGUID, destAppName, protocol string, startPort, endPort int) (Warnings, error) {
    24  	var allWarnings Warnings
    25  
    26  	srcApp, warnings, err := actor.CloudControllerClient.GetApplicationByNameAndSpace(srcAppName, srcSpaceGUID)
    27  	allWarnings = append(allWarnings, warnings...)
    28  	if err != nil {
    29  		return allWarnings, err
    30  	}
    31  
    32  	destApp, warnings, err := actor.CloudControllerClient.GetApplicationByNameAndSpace(destAppName, destSpaceGUID)
    33  	allWarnings = append(allWarnings, warnings...)
    34  	if err != nil {
    35  		return allWarnings, err
    36  	}
    37  
    38  	err = actor.NetworkingClient.CreatePolicies([]cfnetv1.Policy{
    39  		{
    40  			Source: cfnetv1.PolicySource{
    41  				ID: srcApp.GUID,
    42  			},
    43  			Destination: cfnetv1.PolicyDestination{
    44  				ID:       destApp.GUID,
    45  				Protocol: cfnetv1.PolicyProtocol(protocol),
    46  				Ports: cfnetv1.Ports{
    47  					Start: startPort,
    48  					End:   endPort,
    49  				},
    50  			},
    51  		},
    52  	})
    53  	return allWarnings, err
    54  }
    55  
    56  func (actor Actor) NetworkPoliciesBySpace(spaceGUID string) ([]Policy, Warnings, error) {
    57  	var allWarnings Warnings
    58  
    59  	applications, warnings, err := actor.CloudControllerClient.GetApplications(ccv3.Query{
    60  		Key:    ccv3.SpaceGUIDFilter,
    61  		Values: []string{spaceGUID},
    62  	})
    63  	allWarnings = append(allWarnings, warnings...)
    64  	if err != nil {
    65  		return []Policy{}, allWarnings, err
    66  	}
    67  
    68  	policies, warnings, err := actor.getPoliciesForApplications(applications)
    69  	allWarnings = append(allWarnings, warnings...)
    70  	if err != nil {
    71  		return []Policy{}, allWarnings, err
    72  	}
    73  
    74  	return policies, allWarnings, nil
    75  }
    76  
    77  func (actor Actor) NetworkPoliciesBySpaceAndAppName(spaceGUID string, srcAppName string) ([]Policy, Warnings, error) {
    78  	var allWarnings Warnings
    79  
    80  	srcApp, warnings, err := actor.CloudControllerClient.GetApplicationByNameAndSpace(srcAppName, spaceGUID)
    81  	allWarnings = append(allWarnings, warnings...)
    82  	if err != nil {
    83  		return []Policy{}, allWarnings, err
    84  	}
    85  
    86  	policies, warnings, err := actor.getPoliciesForApplications([]resources.Application{srcApp})
    87  	allWarnings = append(allWarnings, warnings...)
    88  	if err != nil {
    89  		return []Policy{}, allWarnings, err
    90  	}
    91  
    92  	return policies, allWarnings, nil
    93  }
    94  
    95  func (actor Actor) RemoveNetworkPolicy(srcSpaceGUID, srcAppName, destSpaceGUID, destAppName, protocol string, startPort, endPort int) (Warnings, error) {
    96  	var allWarnings Warnings
    97  
    98  	srcApp, warnings, err := actor.CloudControllerClient.GetApplicationByNameAndSpace(srcAppName, srcSpaceGUID)
    99  	allWarnings = append(allWarnings, warnings...)
   100  	if err != nil {
   101  		return allWarnings, err
   102  	}
   103  
   104  	destApp, warnings, err := actor.CloudControllerClient.GetApplicationByNameAndSpace(destAppName, destSpaceGUID)
   105  	allWarnings = append(allWarnings, warnings...)
   106  	if err != nil {
   107  		return allWarnings, err
   108  	}
   109  
   110  	policyToRemove := cfnetv1.Policy{
   111  		Source: cfnetv1.PolicySource{
   112  			ID: srcApp.GUID,
   113  		},
   114  		Destination: cfnetv1.PolicyDestination{
   115  			ID:       destApp.GUID,
   116  			Protocol: cfnetv1.PolicyProtocol(protocol),
   117  			Ports: cfnetv1.Ports{
   118  				Start: startPort,
   119  				End:   endPort,
   120  			},
   121  		},
   122  	}
   123  
   124  	v1Policies, err := actor.NetworkingClient.ListPolicies(srcApp.GUID)
   125  	if err != nil {
   126  		return allWarnings, err
   127  	}
   128  
   129  	for _, v1Policy := range v1Policies {
   130  		if v1Policy == policyToRemove {
   131  			return allWarnings, actor.NetworkingClient.RemovePolicies([]cfnetv1.Policy{policyToRemove})
   132  		}
   133  	}
   134  
   135  	return allWarnings, actionerror.PolicyDoesNotExistError{}
   136  }
   137  
   138  func filterPoliciesWithoutMatchingSourceGUIDs(v1Policies []cfnetv1.Policy, srcAppGUIDs []string) []cfnetv1.Policy {
   139  	srcGUIDsSet := map[string]struct{}{}
   140  	for _, srcGUID := range srcAppGUIDs {
   141  		srcGUIDsSet[srcGUID] = struct{}{}
   142  	}
   143  
   144  	var toReturn []cfnetv1.Policy
   145  	for _, policy := range v1Policies {
   146  		if _, ok := srcGUIDsSet[policy.Source.ID]; ok {
   147  			toReturn = append(toReturn, policy)
   148  		}
   149  	}
   150  
   151  	return toReturn
   152  }
   153  
   154  func uniqueSpaceGUIDs(applications []resources.Application) []string {
   155  	var spaceGUIDs []string
   156  	occurrences := map[string]struct{}{}
   157  	for _, app := range applications {
   158  		if _, ok := occurrences[app.SpaceGUID]; !ok {
   159  			spaceGUIDs = append(spaceGUIDs, app.SpaceGUID)
   160  			occurrences[app.SpaceGUID] = struct{}{}
   161  		}
   162  	}
   163  	return spaceGUIDs
   164  }
   165  
   166  func uniqueOrgGUIDs(spaces []resources.Space) []string {
   167  	var orgGUIDs []string
   168  	occurrences := map[string]struct{}{}
   169  	for _, space := range spaces {
   170  		orgGUID := space.Relationships[constant.RelationshipTypeOrganization].GUID
   171  
   172  		if _, ok := occurrences[orgGUID]; !ok {
   173  			orgGUIDs = append(orgGUIDs, orgGUID)
   174  			occurrences[orgGUID] = struct{}{}
   175  		}
   176  	}
   177  	return orgGUIDs
   178  }
   179  
   180  func uniqueDestGUIDs(policies []cfnetv1.Policy) []string {
   181  	var destAppGUIDs []string
   182  	occurrences := map[string]struct{}{}
   183  	for _, policy := range policies {
   184  		if _, ok := occurrences[policy.Destination.ID]; !ok {
   185  			destAppGUIDs = append(destAppGUIDs, policy.Destination.ID)
   186  			occurrences[policy.Destination.ID] = struct{}{}
   187  		}
   188  	}
   189  	return destAppGUIDs
   190  }
   191  
   192  func (actor Actor) orgNamesBySpaceGUID(spaces []resources.Space) (map[string]string, ccv3.Warnings, error) {
   193  	orgs, warnings, err := actor.CloudControllerClient.GetOrganizations(ccv3.Query{
   194  		Key:    ccv3.GUIDFilter,
   195  		Values: uniqueOrgGUIDs(spaces),
   196  	})
   197  	if err != nil {
   198  		return nil, warnings, err
   199  	}
   200  
   201  	orgNamesByGUID := lookuptable.NameFromGUID(orgs)
   202  
   203  	orgNamesBySpaceGUID := make(map[string]string, len(spaces))
   204  	for _, space := range spaces {
   205  		orgGUID := space.Relationships[constant.RelationshipTypeOrganization].GUID
   206  		orgNamesBySpaceGUID[space.GUID] = orgNamesByGUID[orgGUID]
   207  	}
   208  
   209  	return orgNamesBySpaceGUID, warnings, nil
   210  }
   211  
   212  func (actor Actor) getPoliciesForApplications(applications []resources.Application) ([]Policy, ccv3.Warnings, error) {
   213  	var allWarnings ccv3.Warnings
   214  
   215  	var srcAppGUIDs []string
   216  	for _, app := range applications {
   217  		srcAppGUIDs = append(srcAppGUIDs, app.GUID)
   218  	}
   219  
   220  	v1Policies := []cfnetv1.Policy{}
   221  
   222  	_, err := batcher.RequestByGUID(srcAppGUIDs, func(guids []string) (ccv3.Warnings, error) {
   223  		batch, err := actor.NetworkingClient.ListPolicies(guids...)
   224  		if err != nil {
   225  			return nil, err
   226  		}
   227  		v1Policies = append(v1Policies, batch...)
   228  		return nil, err
   229  	})
   230  
   231  	if err != nil {
   232  		return []Policy{}, allWarnings, err
   233  	}
   234  
   235  	// ListPolicies will return policies with the app guids in either the source or destination.
   236  	// It needs to be further filtered to only get policies with the app guids in the source.
   237  	v1Policies = filterPoliciesWithoutMatchingSourceGUIDs(v1Policies, srcAppGUIDs)
   238  
   239  	destAppGUIDs := uniqueDestGUIDs(v1Policies)
   240  
   241  	var destApplications []resources.Application
   242  
   243  	warnings, err := batcher.RequestByGUID(destAppGUIDs, func(guids []string) (ccv3.Warnings, error) {
   244  		batch, warnings, err := actor.CloudControllerClient.GetApplications(ccv3.Query{
   245  			Key:    ccv3.GUIDFilter,
   246  			Values: guids,
   247  		})
   248  		destApplications = append(destApplications, batch...)
   249  		return warnings, err
   250  	})
   251  	allWarnings = append(allWarnings, warnings...)
   252  	if err != nil {
   253  		return []Policy{}, allWarnings, err
   254  	}
   255  
   256  	applications = append(applications, destApplications...)
   257  
   258  	spaces, _, warnings, err := actor.CloudControllerClient.GetSpaces(ccv3.Query{
   259  		Key:    ccv3.GUIDFilter,
   260  		Values: uniqueSpaceGUIDs(applications),
   261  	})
   262  	allWarnings = append(allWarnings, warnings...)
   263  	if err != nil {
   264  		return []Policy{}, allWarnings, err
   265  	}
   266  
   267  	spaceNamesByGUID := lookuptable.NameFromGUID(spaces)
   268  
   269  	orgNamesBySpaceGUID, warnings, err := actor.orgNamesBySpaceGUID(spaces)
   270  	allWarnings = append(allWarnings, warnings...)
   271  	if err != nil {
   272  		return []Policy{}, allWarnings, err
   273  	}
   274  
   275  	appByGUID := lookuptable.AppFromGUID(applications)
   276  
   277  	var policies []Policy
   278  	for _, v1Policy := range v1Policies {
   279  		destination := appByGUID[v1Policy.Destination.ID]
   280  
   281  		policies = append(policies, Policy{
   282  			SourceName:           appByGUID[v1Policy.Source.ID].Name,
   283  			DestinationName:      destination.Name,
   284  			Protocol:             string(v1Policy.Destination.Protocol),
   285  			StartPort:            v1Policy.Destination.Ports.Start,
   286  			EndPort:              v1Policy.Destination.Ports.End,
   287  			DestinationSpaceName: spaceNamesByGUID[destination.SpaceGUID],
   288  			DestinationOrgName:   orgNamesBySpaceGUID[destination.SpaceGUID],
   289  		})
   290  	}
   291  
   292  	return policies, allWarnings, nil
   293  }