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 }