@@ -36,8 +36,9 @@ import (
3636// This includes target port generation for imported services, as well as
3737// k8s service creation per imported service.
3838type Manager struct {
39- client client.Client
40- ports * portManager
39+ client client.Client
40+ crdMode bool
41+ ports * portManager
4142
4243 logger * logrus.Entry
4344}
@@ -103,14 +104,6 @@ func (m *Manager) DeleteLegacyExport(namespace string, exportSpec *api.ExportSpe
103104func (m * Manager ) AddImport (ctx context.Context , imp * v1alpha1.Import ) error {
104105 m .logger .Infof ("Adding import '%s/%s'." , imp .Namespace , imp .Name )
105106
106- // TODO: port manager should map ports to imports, and be able to detect conflicts
107- port , err := m .ports .Lease (imp .Spec .TargetPort )
108- if err != nil {
109- return fmt .Errorf ("cannot generate listening port: %w" , err )
110- }
111-
112- imp .Spec .TargetPort = port
113-
114107 newService := & v1.Service {
115108 ObjectMeta : metav1.ObjectMeta {
116109 Name : imp .Name ,
@@ -130,26 +123,59 @@ func (m *Manager) AddImport(ctx context.Context, imp *v1alpha1.Import) error {
130123 }
131124
132125 var oldService v1.Service
133- err = m .client .Get (
126+ var create bool
127+ err := m .client .Get (
134128 ctx ,
135129 types.NamespacedName {
136130 Name : imp .Name ,
137131 Namespace : imp .Namespace ,
138132 },
139133 & oldService )
140134 if err != nil {
141- if errors .IsNotFound (err ) {
142- return m . client . Create ( ctx , newService )
135+ if ! errors .IsNotFound (err ) {
136+ return err
143137 }
144138
145- return err
139+ create = true
146140 }
147141
148- if serviceChanged (& oldService , newService ) {
149- return m .client .Update (ctx , newService )
142+ // if service exists, and import specifies a random (0) target port,
143+ // then use existing service target port instead of allocating a new port
144+ if ! create && len (oldService .Spec .Ports ) == 1 && imp .Spec .TargetPort == 0 {
145+ imp .Spec .TargetPort = uint16 (oldService .Spec .Ports [0 ].TargetPort .IntVal )
150146 }
151147
152- return nil
148+ newPort := imp .Spec .TargetPort == 0
149+
150+ fullName := imp .Namespace + "/" + imp .Name
151+ port , err := m .ports .Lease (fullName , imp .Spec .TargetPort )
152+ if err != nil {
153+ return fmt .Errorf ("cannot generate listening port: %w" , err )
154+ }
155+
156+ if newPort {
157+ imp .Spec .TargetPort = port
158+ newService .Spec .Ports [0 ].TargetPort = intstr .FromInt32 (int32 (port ))
159+
160+ if m .crdMode {
161+ if err := m .client .Update (ctx , imp ); err != nil {
162+ m .ports .Release (port )
163+ return err
164+ }
165+ }
166+ }
167+
168+ if create {
169+ err = m .client .Create (ctx , newService )
170+ } else if serviceChanged (& oldService , newService ) {
171+ err = m .client .Update (ctx , newService )
172+ }
173+
174+ if err != nil && newPort {
175+ m .ports .Release (port )
176+ }
177+
178+ return err
153179}
154180
155181// DeleteImport removes the listening socket of a previously imported service.
@@ -193,12 +219,13 @@ func serviceChanged(svc1, svc2 *v1.Service) bool {
193219}
194220
195221// NewManager returns a new control manager.
196- func NewManager (cl client.Client ) * Manager {
222+ func NewManager (cl client.Client , crdMode bool ) * Manager {
197223 logger := logrus .WithField ("component" , "controlplane.control.manager" )
198224
199225 return & Manager {
200- client : cl ,
201- ports : newPortManager (),
202- logger : logger ,
226+ client : cl ,
227+ crdMode : crdMode ,
228+ ports : newPortManager (),
229+ logger : logger ,
203230 }
204231}
0 commit comments