github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/portforward/entry_manager.go (about) 1 /* 2 Copyright 2019 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package portforward 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "sync" 24 25 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants" 26 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" 27 eventV2 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event/v2" 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/output" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" 30 ) 31 32 var ( 33 portForwardEvent = func(entry *portForwardEntry) { 34 event.PortForwarded( 35 int32(entry.localPort), 36 entry.resource.Port, 37 entry.podName, 38 entry.containerName, 39 entry.resource.Namespace, 40 entry.portName, 41 string(entry.resource.Type), 42 entry.resource.Name, 43 entry.resource.Address) 44 } 45 portForwardEventV2 = func(entry *portForwardEntry) { 46 eventV2.PortForwarded( 47 int32(entry.localPort), 48 entry.resource.Port, 49 entry.podName, 50 entry.containerName, 51 entry.resource.Namespace, 52 entry.portName, 53 string(entry.resource.Type), 54 entry.resource.Name, 55 entry.resource.Address) 56 } 57 ) 58 59 // EntryManager handles forwarding entries and keeping track of 60 // forwarded ports and resources. 61 type EntryManager struct { 62 entryForwarder EntryForwarder 63 64 // forwardedPorts serves as a synchronized set of ports we've forwarded. 65 forwardedPorts util.PortSet 66 67 // forwardedResources is a map of portForwardEntry key (string) -> portForwardEntry 68 forwardedResources sync.Map 69 } 70 71 // NewEntryManager returns a new port forward entry manager to keep track 72 // of forwarded ports and resources 73 func NewEntryManager(entryForwarder EntryForwarder) *EntryManager { 74 return &EntryManager{ 75 entryForwarder: entryForwarder, 76 } 77 } 78 79 func (b *EntryManager) forwardPortForwardEntry(ctx context.Context, out io.Writer, entry *portForwardEntry) { 80 out, ctx = output.WithEventContext(ctx, out, constants.PortForward, fmt.Sprintf("%s/%s", entry.resource.Type, entry.resource.Name)) 81 82 // Check if this resource has already been forwarded 83 if _, found := b.forwardedResources.LoadOrStore(entry.key(), entry); found { 84 return 85 } 86 87 if err := b.entryForwarder.Forward(ctx, entry); err == nil { 88 output.Green.Fprintln( 89 out, 90 fmt.Sprintf("Port forwarding %s/%s in namespace %s, remote port %s -> http://%s:%d", 91 entry.resource.Type, 92 entry.resource.Name, 93 entry.resource.Namespace, 94 entry.resource.Port.String(), 95 entry.resource.Address, 96 entry.localPort)) 97 } else { 98 output.Red.Fprintln(out, err) 99 } 100 portForwardEvent(entry) 101 portForwardEventV2(entry) 102 } 103 104 // Start ensures the underlying entryForwarder is ready to forward. 105 func (b *EntryManager) Start(out io.Writer) { 106 b.entryForwarder.Start(out) 107 } 108 109 // Stop terminates all kubectl port-forward commands. 110 func (b *EntryManager) Stop() { 111 b.forwardedResources.Range(func(_, value interface{}) bool { 112 pfe := value.(*portForwardEntry) 113 b.Terminate(pfe) 114 return true 115 }) 116 } 117 118 // Terminate terminates a single port forward entry 119 func (b *EntryManager) Terminate(p *portForwardEntry) { 120 b.forwardedResources.Delete(p.key()) 121 b.forwardedPorts.Delete(p.localPort) 122 b.entryForwarder.Terminate(p) 123 }