@@ -4,26 +4,59 @@ import (
4
4
"fmt"
5
5
"github.com/compose-spec/compose-go/v2/types"
6
6
"github.com/psviderski/uncloud/pkg/api"
7
+ "net/netip"
8
+ "strconv"
7
9
)
8
10
9
11
const PortsExtensionKey = "x-ports"
10
12
11
13
type PortsSource []string
12
14
13
- // TransformServicesPortsExtension transforms the ports extension of all services in the project by replacing a string
14
- // representation of each port with a parsed PortSpec.
15
+ // transformServicesPortsExtension transforms both standard 'ports' and 'x-ports' to PortSpecs.
15
16
func transformServicesPortsExtension (project * types.Project ) (* types.Project , error ) {
16
17
return project .WithServicesTransform (func (name string , service types.ServiceConfig ) (types.ServiceConfig , error ) {
17
- ports , ok := service .Extensions [PortsExtensionKey ].(PortsSource )
18
- if ! ok {
19
- return service , nil
18
+ // Check for mutual exclusivity
19
+ hasStandardPorts := len (service .Ports ) > 0
20
+ hasXPorts := service .Extensions [PortsExtensionKey ] != nil
21
+
22
+ if hasStandardPorts && hasXPorts {
23
+ return service , fmt .Errorf ("service %q cannot specify both 'ports' and 'x-ports' directives, use only one" , name )
20
24
}
21
25
22
- specs , err := transformPortsExtension (ports )
23
- if err != nil {
24
- return service , err
26
+ var (
27
+ specs []api.PortSpec
28
+ err error
29
+ )
30
+
31
+ if hasStandardPorts {
32
+ // Convert standard ports directly to api.PortSpec
33
+ specs , err = convertStandardPortsToPortSpecs (service .Ports )
34
+ if err != nil {
35
+ return service , fmt .Errorf ("convert standard ports for service %q: %w" , name , err )
36
+ }
37
+ } else if hasXPorts {
38
+ // Use existing x-ports string-based processing for backward compatibility
39
+ var portsSource PortsSource
40
+ var ok bool
41
+ portsSource , ok = service .Extensions [PortsExtensionKey ].(PortsSource )
42
+ if ! ok {
43
+ return service , nil
44
+ }
45
+
46
+ // Parse the port strings using existing logic
47
+ specs , err = transformPortsExtension (portsSource )
48
+ if err != nil {
49
+ return service , err
50
+ }
51
+ } else {
52
+ // No ports specified
53
+ return service , nil
25
54
}
26
55
56
+ // Ensure extensions map exists before setting the port specs
57
+ if service .Extensions == nil {
58
+ service .Extensions = make (types.Extensions )
59
+ }
27
60
service .Extensions [PortsExtensionKey ] = specs
28
61
return service , nil
29
62
})
@@ -41,3 +74,54 @@ func transformPortsExtension(ports PortsSource) ([]api.PortSpec, error) {
41
74
42
75
return specs , nil
43
76
}
77
+
78
+ // convertServicePortConfigToPortSpec converts types.ServicePortConfig directly to api.PortSpec
79
+ func convertServicePortConfigToPortSpec (port types.ServicePortConfig ) (api.PortSpec , error ) {
80
+ spec := api.PortSpec {
81
+ ContainerPort : uint16 (port .Target ),
82
+ Protocol : port .Protocol ,
83
+ Mode : port .Mode ,
84
+ }
85
+ // Set published port if specified
86
+ if port .Published != "" {
87
+ publishedPort , err := strconv .ParseUint (port .Published , 10 , 16 )
88
+ if err != nil {
89
+ return spec , fmt .Errorf ("invalid published port %q: %w" , port .Published , err )
90
+ }
91
+ spec .PublishedPort = uint16 (publishedPort )
92
+ }
93
+
94
+ // Set host IP if specified
95
+ if port .HostIP != "" {
96
+ hostIP , err := netip .ParseAddr (port .HostIP )
97
+ if err != nil {
98
+ return spec , fmt .Errorf ("invalid host IP %q: %w" , port .HostIP , err )
99
+ }
100
+ spec .HostIP = hostIP
101
+ }
102
+
103
+ // Apply defaults according to uncloud
104
+ spec .AdjustUncloudMode ()
105
+
106
+ // Validate the resulting spec
107
+ if err := spec .Validate (); err != nil {
108
+ return spec , fmt .Errorf ("invalid port configuration: %w" , err )
109
+ }
110
+
111
+ return spec , nil
112
+ }
113
+
114
+ // convertStandardPortsToPortSpecs converts []types.ServicePortConfig directly to api.PortSpecs.
115
+ func convertStandardPortsToPortSpecs (ports []types.ServicePortConfig ) ([]api.PortSpec , error ) {
116
+ var specs = make ([]api.PortSpec , 0 , len (ports ))
117
+
118
+ for _ , port := range ports {
119
+ spec , err := convertServicePortConfigToPortSpec (port )
120
+ if err != nil {
121
+ return nil , err
122
+ }
123
+ specs = append (specs , spec )
124
+ }
125
+
126
+ return specs , nil
127
+ }
0 commit comments