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