github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/command/stack/kubernetes/conversion_test.go (about) 1 package kubernetes 2 3 import ( 4 "testing" 5 6 . "github.com/docker/cli/internal/test/builders" // Import builders to get the builder function as package function 7 "github.com/docker/compose-on-kubernetes/api/labels" 8 "github.com/docker/docker/api/types/swarm" 9 "gotest.tools/v3/assert" 10 appsv1beta2 "k8s.io/api/apps/v1beta2" 11 apiv1 "k8s.io/api/core/v1" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 apimachineryTypes "k8s.io/apimachinery/pkg/types" 14 apimachineryUtil "k8s.io/apimachinery/pkg/util/intstr" 15 ) 16 17 func TestReplicasConversionNeedsAService(t *testing.T) { 18 replicas := appsv1beta2.ReplicaSetList{ 19 Items: []appsv1beta2.ReplicaSet{makeReplicaSet("unknown", 0, 0)}, 20 } 21 services := apiv1.ServiceList{} 22 _, err := convertToServices(&replicas, &appsv1beta2.DaemonSetList{}, &services) 23 assert.ErrorContains(t, err, "could not find service") 24 } 25 26 func TestKubernetesServiceToSwarmServiceConversion(t *testing.T) { 27 testCases := []struct { 28 doc string 29 replicas *appsv1beta2.ReplicaSetList 30 services *apiv1.ServiceList 31 expectedServices []swarm.Service 32 }{ 33 { 34 doc: "Match replicas with headless stack services", 35 replicas: &appsv1beta2.ReplicaSetList{ 36 Items: []appsv1beta2.ReplicaSet{ 37 makeReplicaSet("service1", 2, 5), 38 makeReplicaSet("service2", 3, 3), 39 }, 40 }, 41 services: &apiv1.ServiceList{ 42 Items: []apiv1.Service{ 43 makeKubeService("service1", "stack", "uid1", apiv1.ServiceTypeClusterIP, nil), 44 makeKubeService("service2", "stack", "uid2", apiv1.ServiceTypeClusterIP, nil), 45 makeKubeService("service3", "other-stack", "uid2", apiv1.ServiceTypeClusterIP, nil), 46 }, 47 }, 48 expectedServices: []swarm.Service{ 49 makeSwarmService(t, "stack_service1", "uid1", ReplicatedService(5), ServiceStatus(5, 2)), 50 makeSwarmService(t, "stack_service2", "uid2", ReplicatedService(3), ServiceStatus(3, 3)), 51 }, 52 }, 53 { 54 doc: "Headless service and LoadBalancer Service are tied to the same Swarm service", 55 replicas: &appsv1beta2.ReplicaSetList{ 56 Items: []appsv1beta2.ReplicaSet{ 57 makeReplicaSet("service", 1, 1), 58 }, 59 }, 60 services: &apiv1.ServiceList{ 61 Items: []apiv1.Service{ 62 makeKubeService("service", "stack", "uid1", apiv1.ServiceTypeClusterIP, nil), 63 makeKubeService("service-published", "stack", "uid2", apiv1.ServiceTypeLoadBalancer, []apiv1.ServicePort{ 64 { 65 Port: 80, 66 TargetPort: apimachineryUtil.FromInt(80), 67 Protocol: apiv1.ProtocolTCP, 68 }, 69 }), 70 }, 71 }, 72 expectedServices: []swarm.Service{ 73 makeSwarmService(t, "stack_service", "uid1", 74 ReplicatedService(1), 75 ServiceStatus(1, 1), 76 withPort(swarm.PortConfig{ 77 PublishMode: swarm.PortConfigPublishModeIngress, 78 PublishedPort: 80, 79 TargetPort: 80, 80 Protocol: swarm.PortConfigProtocolTCP, 81 }), 82 ), 83 }, 84 }, 85 { 86 doc: "Headless service and NodePort Service are tied to the same Swarm service", 87 replicas: &appsv1beta2.ReplicaSetList{ 88 Items: []appsv1beta2.ReplicaSet{ 89 makeReplicaSet("service", 1, 1), 90 }, 91 }, 92 services: &apiv1.ServiceList{ 93 Items: []apiv1.Service{ 94 makeKubeService("service", "stack", "uid1", apiv1.ServiceTypeClusterIP, nil), 95 makeKubeService("service-random-ports", "stack", "uid2", apiv1.ServiceTypeNodePort, []apiv1.ServicePort{ 96 { 97 Port: 35666, 98 TargetPort: apimachineryUtil.FromInt(80), 99 Protocol: apiv1.ProtocolTCP, 100 }, 101 }), 102 }, 103 }, 104 expectedServices: []swarm.Service{ 105 makeSwarmService(t, "stack_service", "uid1", 106 ReplicatedService(1), 107 ServiceStatus(1, 1), 108 withPort(swarm.PortConfig{ 109 PublishMode: swarm.PortConfigPublishModeHost, 110 PublishedPort: 35666, 111 TargetPort: 80, 112 Protocol: swarm.PortConfigProtocolTCP, 113 }), 114 ), 115 }, 116 }, 117 } 118 119 for _, tc := range testCases { 120 tc := tc 121 t.Run(tc.doc, func(t *testing.T) { 122 swarmServices, err := convertToServices(tc.replicas, &appsv1beta2.DaemonSetList{}, tc.services) 123 assert.NilError(t, err) 124 assert.DeepEqual(t, tc.expectedServices, swarmServices) 125 }) 126 } 127 } 128 129 func makeReplicaSet(service string, available, replicas int32) appsv1beta2.ReplicaSet { 130 return appsv1beta2.ReplicaSet{ 131 ObjectMeta: metav1.ObjectMeta{ 132 Labels: map[string]string{ 133 labels.ForServiceName: service, 134 }, 135 }, 136 Spec: appsv1beta2.ReplicaSetSpec{ 137 Template: apiv1.PodTemplateSpec{ 138 Spec: apiv1.PodSpec{ 139 Containers: []apiv1.Container{ 140 { 141 Image: "image", 142 }, 143 }, 144 }, 145 }, 146 }, 147 Status: appsv1beta2.ReplicaSetStatus{ 148 AvailableReplicas: available, 149 Replicas: replicas, 150 }, 151 } 152 } 153 154 func makeKubeService(service, stack, uid string, serviceType apiv1.ServiceType, ports []apiv1.ServicePort) apiv1.Service { 155 return apiv1.Service{ 156 ObjectMeta: metav1.ObjectMeta{ 157 Labels: map[string]string{ 158 labels.ForStackName: stack, 159 }, 160 Name: service, 161 UID: apimachineryTypes.UID(uid), 162 }, 163 Spec: apiv1.ServiceSpec{ 164 Type: serviceType, 165 Ports: ports, 166 }, 167 } 168 } 169 170 // TODO convertToServices currently doesn't set swarm.EndpointSpec.Ports 171 func withPort(port swarm.PortConfig) func(*swarm.Service) { 172 return func(service *swarm.Service) { 173 if service.Endpoint.Ports == nil { 174 service.Endpoint.Ports = make([]swarm.PortConfig, 0) 175 } 176 service.Endpoint.Ports = append(service.Endpoint.Ports, port) 177 } 178 } 179 180 func makeSwarmService(t *testing.T, name, id string, opts ...func(*swarm.Service)) swarm.Service { 181 t.Helper() 182 options := []func(*swarm.Service){ServiceID(id), ServiceName(name), ServiceImage("image")} 183 options = append(options, opts...) 184 return *Service(options...) 185 }