k8s.io/kubernetes@v1.29.3/pkg/apis/core/v1/conversion.go (about) 1 /* 2 Copyright 2015 The Kubernetes 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 v1 18 19 import ( 20 "fmt" 21 "reflect" 22 23 v1 "k8s.io/api/core/v1" 24 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/conversion" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apimachinery/pkg/util/validation/field" 29 "k8s.io/kubernetes/pkg/apis/apps" 30 "k8s.io/kubernetes/pkg/apis/core" 31 utilpointer "k8s.io/utils/pointer" 32 ) 33 34 func addConversionFuncs(scheme *runtime.Scheme) error { 35 // Add field conversion funcs. 36 err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Pod"), 37 func(label, value string) (string, string, error) { 38 switch label { 39 case "metadata.name", 40 "metadata.namespace", 41 "spec.nodeName", 42 "spec.restartPolicy", 43 "spec.schedulerName", 44 "spec.serviceAccountName", 45 "spec.hostNetwork", 46 "status.phase", 47 "status.podIP", 48 "status.podIPs", 49 "status.nominatedNodeName": 50 return label, value, nil 51 // This is for backwards compatibility with old v1 clients which send spec.host 52 case "spec.host": 53 return "spec.nodeName", value, nil 54 default: 55 return "", "", fmt.Errorf("field label not supported: %s", label) 56 } 57 }, 58 ) 59 if err != nil { 60 return err 61 } 62 err = scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Node"), 63 func(label, value string) (string, string, error) { 64 switch label { 65 case "metadata.name": 66 return label, value, nil 67 case "spec.unschedulable": 68 return label, value, nil 69 default: 70 return "", "", fmt.Errorf("field label not supported: %s", label) 71 } 72 }, 73 ) 74 if err != nil { 75 return err 76 } 77 err = scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("ReplicationController"), 78 func(label, value string) (string, string, error) { 79 switch label { 80 case "metadata.name", 81 "metadata.namespace", 82 "status.replicas": 83 return label, value, nil 84 default: 85 return "", "", fmt.Errorf("field label not supported: %s", label) 86 } 87 }) 88 if err != nil { 89 return err 90 } 91 if err := AddFieldLabelConversionsForEvent(scheme); err != nil { 92 return err 93 } 94 if err := AddFieldLabelConversionsForNamespace(scheme); err != nil { 95 return err 96 } 97 if err := AddFieldLabelConversionsForSecret(scheme); err != nil { 98 return err 99 } 100 return nil 101 } 102 103 func Convert_v1_ReplicationController_To_apps_ReplicaSet(in *v1.ReplicationController, out *apps.ReplicaSet, s conversion.Scope) error { 104 out.ObjectMeta = in.ObjectMeta 105 if err := Convert_v1_ReplicationControllerSpec_To_apps_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil { 106 return err 107 } 108 if err := Convert_v1_ReplicationControllerStatus_To_apps_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil { 109 return err 110 } 111 return nil 112 } 113 114 func Convert_v1_ReplicationControllerSpec_To_apps_ReplicaSetSpec(in *v1.ReplicationControllerSpec, out *apps.ReplicaSetSpec, s conversion.Scope) error { 115 out.Replicas = *in.Replicas 116 out.MinReadySeconds = in.MinReadySeconds 117 if in.Selector != nil { 118 out.Selector = new(metav1.LabelSelector) 119 metav1.Convert_Map_string_To_string_To_v1_LabelSelector(&in.Selector, out.Selector, s) 120 } 121 if in.Template != nil { 122 if err := Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in.Template, &out.Template, s); err != nil { 123 return err 124 } 125 } 126 return nil 127 } 128 129 func Convert_v1_ReplicationControllerStatus_To_apps_ReplicaSetStatus(in *v1.ReplicationControllerStatus, out *apps.ReplicaSetStatus, s conversion.Scope) error { 130 out.Replicas = in.Replicas 131 out.FullyLabeledReplicas = in.FullyLabeledReplicas 132 out.ReadyReplicas = in.ReadyReplicas 133 out.AvailableReplicas = in.AvailableReplicas 134 out.ObservedGeneration = in.ObservedGeneration 135 for _, cond := range in.Conditions { 136 out.Conditions = append(out.Conditions, apps.ReplicaSetCondition{ 137 Type: apps.ReplicaSetConditionType(cond.Type), 138 Status: core.ConditionStatus(cond.Status), 139 LastTransitionTime: cond.LastTransitionTime, 140 Reason: cond.Reason, 141 Message: cond.Message, 142 }) 143 } 144 return nil 145 } 146 147 func Convert_apps_ReplicaSet_To_v1_ReplicationController(in *apps.ReplicaSet, out *v1.ReplicationController, s conversion.Scope) error { 148 out.ObjectMeta = in.ObjectMeta 149 if err := Convert_apps_ReplicaSetSpec_To_v1_ReplicationControllerSpec(&in.Spec, &out.Spec, s); err != nil { 150 fieldErr, ok := err.(*field.Error) 151 if !ok { 152 return err 153 } 154 if out.Annotations == nil { 155 out.Annotations = make(map[string]string) 156 } 157 out.Annotations[v1.NonConvertibleAnnotationPrefix+"/"+fieldErr.Field] = reflect.ValueOf(fieldErr.BadValue).String() 158 } 159 if err := Convert_apps_ReplicaSetStatus_To_v1_ReplicationControllerStatus(&in.Status, &out.Status, s); err != nil { 160 return err 161 } 162 return nil 163 } 164 165 func Convert_apps_ReplicaSetSpec_To_v1_ReplicationControllerSpec(in *apps.ReplicaSetSpec, out *v1.ReplicationControllerSpec, s conversion.Scope) error { 166 out.Replicas = new(int32) 167 *out.Replicas = in.Replicas 168 out.MinReadySeconds = in.MinReadySeconds 169 var invalidErr error 170 if in.Selector != nil { 171 invalidErr = metav1.Convert_v1_LabelSelector_To_Map_string_To_string(in.Selector, &out.Selector, s) 172 } 173 out.Template = new(v1.PodTemplateSpec) 174 if err := Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, out.Template, s); err != nil { 175 return err 176 } 177 return invalidErr 178 } 179 180 func Convert_apps_ReplicaSetStatus_To_v1_ReplicationControllerStatus(in *apps.ReplicaSetStatus, out *v1.ReplicationControllerStatus, s conversion.Scope) error { 181 out.Replicas = in.Replicas 182 out.FullyLabeledReplicas = in.FullyLabeledReplicas 183 out.ReadyReplicas = in.ReadyReplicas 184 out.AvailableReplicas = in.AvailableReplicas 185 out.ObservedGeneration = in.ObservedGeneration 186 for _, cond := range in.Conditions { 187 out.Conditions = append(out.Conditions, v1.ReplicationControllerCondition{ 188 Type: v1.ReplicationControllerConditionType(cond.Type), 189 Status: v1.ConditionStatus(cond.Status), 190 LastTransitionTime: cond.LastTransitionTime, 191 Reason: cond.Reason, 192 Message: cond.Message, 193 }) 194 } 195 return nil 196 } 197 198 func Convert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *core.ReplicationControllerSpec, out *v1.ReplicationControllerSpec, s conversion.Scope) error { 199 out.Replicas = &in.Replicas 200 out.MinReadySeconds = in.MinReadySeconds 201 out.Selector = in.Selector 202 if in.Template != nil { 203 out.Template = new(v1.PodTemplateSpec) 204 if err := Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in.Template, out.Template, s); err != nil { 205 return err 206 } 207 } else { 208 out.Template = nil 209 } 210 return nil 211 } 212 213 func Convert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(in *v1.ReplicationControllerSpec, out *core.ReplicationControllerSpec, s conversion.Scope) error { 214 if in.Replicas != nil { 215 out.Replicas = *in.Replicas 216 } 217 out.MinReadySeconds = in.MinReadySeconds 218 out.Selector = in.Selector 219 if in.Template != nil { 220 out.Template = new(core.PodTemplateSpec) 221 if err := Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in.Template, out.Template, s); err != nil { 222 return err 223 } 224 } else { 225 out.Template = nil 226 } 227 return nil 228 } 229 230 func Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in *core.PodTemplateSpec, out *v1.PodTemplateSpec, s conversion.Scope) error { 231 if err := autoConvert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in, out, s); err != nil { 232 return err 233 } 234 235 // drop init container annotations so they don't take effect on legacy kubelets. 236 // remove this once the oldest supported kubelet no longer honors the annotations over the field. 237 out.Annotations = dropInitContainerAnnotations(out.Annotations) 238 239 return nil 240 } 241 242 func Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in *v1.PodTemplateSpec, out *core.PodTemplateSpec, s conversion.Scope) error { 243 if err := autoConvert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in, out, s); err != nil { 244 return err 245 } 246 247 // drop init container annotations so they don't show up as differences when receiving requests from old clients 248 out.Annotations = dropInitContainerAnnotations(out.Annotations) 249 250 return nil 251 } 252 253 func Convert_v1_PodStatus_To_core_PodStatus(in *v1.PodStatus, out *core.PodStatus, s conversion.Scope) error { 254 if err := autoConvert_v1_PodStatus_To_core_PodStatus(in, out, s); err != nil { 255 return err 256 } 257 258 // If both fields (v1.PodIPs and v1.PodIP) are provided and differ, then PodIP is authoritative for compatibility with older kubelets 259 if (len(in.PodIP) > 0 && len(in.PodIPs) > 0) && (in.PodIP != in.PodIPs[0].IP) { 260 out.PodIPs = []core.PodIP{ 261 { 262 IP: in.PodIP, 263 }, 264 } 265 } 266 // at the this point, autoConvert copied v1.PodIPs -> core.PodIPs 267 // if v1.PodIPs was empty but v1.PodIP is not, then set core.PodIPs[0] with v1.PodIP 268 if len(in.PodIP) > 0 && len(in.PodIPs) == 0 { 269 out.PodIPs = []core.PodIP{ 270 { 271 IP: in.PodIP, 272 }, 273 } 274 } 275 return nil 276 } 277 278 func Convert_core_PodStatus_To_v1_PodStatus(in *core.PodStatus, out *v1.PodStatus, s conversion.Scope) error { 279 if err := autoConvert_core_PodStatus_To_v1_PodStatus(in, out, s); err != nil { 280 return err 281 } 282 // at the this point autoConvert copied core.PodIPs -> v1.PodIPs 283 // v1.PodIP (singular value field, which does not exist in core) needs to 284 // be set with core.PodIPs[0] 285 if len(in.PodIPs) > 0 { 286 out.PodIP = in.PodIPs[0].IP 287 } 288 return nil 289 } 290 291 // The following two v1.PodSpec conversions are done here to support v1.ServiceAccount 292 // as an alias for ServiceAccountName. 293 func Convert_core_PodSpec_To_v1_PodSpec(in *core.PodSpec, out *v1.PodSpec, s conversion.Scope) error { 294 if err := autoConvert_core_PodSpec_To_v1_PodSpec(in, out, s); err != nil { 295 return err 296 } 297 298 // DeprecatedServiceAccount is an alias for ServiceAccountName. 299 out.DeprecatedServiceAccount = in.ServiceAccountName 300 301 if in.SecurityContext != nil { 302 // the host namespace fields have to be handled here for backward compatibility 303 // with v1.0.0 304 out.HostPID = in.SecurityContext.HostPID 305 out.HostNetwork = in.SecurityContext.HostNetwork 306 out.HostIPC = in.SecurityContext.HostIPC 307 out.ShareProcessNamespace = in.SecurityContext.ShareProcessNamespace 308 out.HostUsers = in.SecurityContext.HostUsers 309 } 310 311 return nil 312 } 313 314 func Convert_core_NodeSpec_To_v1_NodeSpec(in *core.NodeSpec, out *v1.NodeSpec, s conversion.Scope) error { 315 if err := autoConvert_core_NodeSpec_To_v1_NodeSpec(in, out, s); err != nil { 316 return err 317 } 318 // at the this point autoConvert copied core.PodCIDRs -> v1.PodCIDRs 319 // v1.PodCIDR (singular value field, which does not exist in core) needs to 320 // be set with core.PodCIDRs[0] 321 if len(in.PodCIDRs) > 0 { 322 out.PodCIDR = in.PodCIDRs[0] 323 } 324 return nil 325 } 326 327 func Convert_v1_NodeSpec_To_core_NodeSpec(in *v1.NodeSpec, out *core.NodeSpec, s conversion.Scope) error { 328 if err := autoConvert_v1_NodeSpec_To_core_NodeSpec(in, out, s); err != nil { 329 return err 330 } 331 // If both fields (v1.PodCIDRs and v1.PodCIDR) are provided and differ, then PodCIDR is authoritative for compatibility with older clients 332 if (len(in.PodCIDR) > 0 && len(in.PodCIDRs) > 0) && (in.PodCIDR != in.PodCIDRs[0]) { 333 out.PodCIDRs = []string{in.PodCIDR} 334 } 335 336 // at the this point, autoConvert copied v1.PodCIDRs -> core.PodCIDRs 337 // if v1.PodCIDRs was empty but v1.PodCIDR is not, then set core.PodCIDRs[0] with v1.PodCIDR 338 if len(in.PodCIDR) > 0 && len(in.PodCIDRs) == 0 { 339 out.PodCIDRs = []string{in.PodCIDR} 340 } 341 return nil 342 } 343 344 func Convert_v1_PodSpec_To_core_PodSpec(in *v1.PodSpec, out *core.PodSpec, s conversion.Scope) error { 345 if err := autoConvert_v1_PodSpec_To_core_PodSpec(in, out, s); err != nil { 346 return err 347 } 348 349 // We support DeprecatedServiceAccount as an alias for ServiceAccountName. 350 // If both are specified, ServiceAccountName (the new field) wins. 351 if in.ServiceAccountName == "" { 352 out.ServiceAccountName = in.DeprecatedServiceAccount 353 } 354 355 // the host namespace fields have to be handled specially for backward compatibility 356 // with v1.0.0 357 if out.SecurityContext == nil { 358 out.SecurityContext = new(core.PodSecurityContext) 359 } 360 out.SecurityContext.HostNetwork = in.HostNetwork 361 out.SecurityContext.HostPID = in.HostPID 362 out.SecurityContext.HostIPC = in.HostIPC 363 out.SecurityContext.ShareProcessNamespace = in.ShareProcessNamespace 364 out.SecurityContext.HostUsers = in.HostUsers 365 366 return nil 367 } 368 369 func Convert_v1_Pod_To_core_Pod(in *v1.Pod, out *core.Pod, s conversion.Scope) error { 370 if err := autoConvert_v1_Pod_To_core_Pod(in, out, s); err != nil { 371 return err 372 } 373 374 // drop init container annotations so they don't show up as differences when receiving requests from old clients 375 out.Annotations = dropInitContainerAnnotations(out.Annotations) 376 377 // Forcing the value of TerminationGracePeriodSeconds to 1 if it is negative. 378 // Just for Pod, not for PodSpec, because we don't want to change the behavior of the PodTemplate. 379 if in.Spec.TerminationGracePeriodSeconds != nil && *in.Spec.TerminationGracePeriodSeconds < 0 { 380 out.Spec.TerminationGracePeriodSeconds = utilpointer.Int64(1) 381 } 382 return nil 383 } 384 385 func Convert_core_Pod_To_v1_Pod(in *core.Pod, out *v1.Pod, s conversion.Scope) error { 386 if err := autoConvert_core_Pod_To_v1_Pod(in, out, s); err != nil { 387 return err 388 } 389 390 // drop init container annotations so they don't take effect on legacy kubelets. 391 // remove this once the oldest supported kubelet no longer honors the annotations over the field. 392 out.Annotations = dropInitContainerAnnotations(out.Annotations) 393 394 // Forcing the value of TerminationGracePeriodSeconds to 1 if it is negative. 395 // Just for Pod, not for PodSpec, because we don't want to change the behavior of the PodTemplate. 396 if in.Spec.TerminationGracePeriodSeconds != nil && *in.Spec.TerminationGracePeriodSeconds < 0 { 397 out.Spec.TerminationGracePeriodSeconds = utilpointer.Int64(1) 398 } 399 return nil 400 } 401 402 func Convert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s conversion.Scope) error { 403 if err := autoConvert_v1_Secret_To_core_Secret(in, out, s); err != nil { 404 return err 405 } 406 407 // StringData overwrites Data 408 if len(in.StringData) > 0 { 409 if out.Data == nil { 410 out.Data = map[string][]byte{} 411 } 412 for k, v := range in.StringData { 413 out.Data[k] = []byte(v) 414 } 415 } 416 417 return nil 418 } 419 420 // +k8s:conversion-fn=copy-only 421 func Convert_v1_ResourceList_To_core_ResourceList(in *v1.ResourceList, out *core.ResourceList, s conversion.Scope) error { 422 if *in == nil { 423 return nil 424 } 425 if *out == nil { 426 *out = make(core.ResourceList, len(*in)) 427 } 428 for key, val := range *in { 429 // Moved to defaults 430 // TODO(#18538): We round up resource values to milli scale to maintain API compatibility. 431 // In the future, we should instead reject values that need rounding. 432 // const milliScale = -3 433 // val.RoundUp(milliScale) 434 435 (*out)[core.ResourceName(key)] = val 436 } 437 return nil 438 } 439 440 func AddFieldLabelConversionsForEvent(scheme *runtime.Scheme) error { 441 return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Event"), 442 func(label, value string) (string, string, error) { 443 switch label { 444 case "involvedObject.kind", 445 "involvedObject.namespace", 446 "involvedObject.name", 447 "involvedObject.uid", 448 "involvedObject.apiVersion", 449 "involvedObject.resourceVersion", 450 "involvedObject.fieldPath", 451 "reason", 452 "reportingComponent", 453 "source", 454 "type", 455 "metadata.namespace", 456 "metadata.name": 457 return label, value, nil 458 default: 459 return "", "", fmt.Errorf("field label not supported: %s", label) 460 } 461 }) 462 } 463 464 func AddFieldLabelConversionsForNamespace(scheme *runtime.Scheme) error { 465 return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Namespace"), 466 func(label, value string) (string, string, error) { 467 switch label { 468 case "status.phase", 469 "metadata.name": 470 return label, value, nil 471 default: 472 return "", "", fmt.Errorf("field label not supported: %s", label) 473 } 474 }) 475 } 476 477 func AddFieldLabelConversionsForSecret(scheme *runtime.Scheme) error { 478 return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Secret"), 479 func(label, value string) (string, string, error) { 480 switch label { 481 case "type", 482 "metadata.namespace", 483 "metadata.name": 484 return label, value, nil 485 default: 486 return "", "", fmt.Errorf("field label not supported: %s", label) 487 } 488 }) 489 } 490 491 var initContainerAnnotations = map[string]bool{ 492 "pod.beta.kubernetes.io/init-containers": true, 493 "pod.alpha.kubernetes.io/init-containers": true, 494 "pod.beta.kubernetes.io/init-container-statuses": true, 495 "pod.alpha.kubernetes.io/init-container-statuses": true, 496 } 497 498 // dropInitContainerAnnotations returns a copy of the annotations with init container annotations removed, 499 // or the original annotations if no init container annotations were present. 500 // 501 // this can be removed once no clients prior to 1.8 are supported, and no kubelets prior to 1.8 can be run 502 // (we don't support kubelets older than 2 versions skewed from the apiserver, but we don't prevent them, either) 503 func dropInitContainerAnnotations(oldAnnotations map[string]string) map[string]string { 504 if len(oldAnnotations) == 0 { 505 return oldAnnotations 506 } 507 508 found := false 509 for k := range initContainerAnnotations { 510 if _, ok := oldAnnotations[k]; ok { 511 found = true 512 break 513 } 514 } 515 if !found { 516 return oldAnnotations 517 } 518 519 newAnnotations := make(map[string]string, len(oldAnnotations)) 520 for k, v := range oldAnnotations { 521 if !initContainerAnnotations[k] { 522 newAnnotations[k] = v 523 } 524 } 525 return newAnnotations 526 } 527 528 // Convert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus is defined outside the autogenerated file for use by other API packages 529 func Convert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(in *core.LoadBalancerStatus, out *v1.LoadBalancerStatus, s conversion.Scope) error { 530 return autoConvert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(in, out, s) 531 } 532 533 // Convert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus is defined outside the autogenerated file for use by other API packages 534 func Convert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(in *v1.LoadBalancerStatus, out *core.LoadBalancerStatus, s conversion.Scope) error { 535 return autoConvert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(in, out, s) 536 } 537 538 // Convert_core_Volume_To_v1_Volume is defined outside the autogenerated file for use by other API packages 539 func Convert_core_Volume_To_v1_Volume(in *core.Volume, out *v1.Volume, s conversion.Scope) error { 540 return autoConvert_core_Volume_To_v1_Volume(in, out, s) 541 } 542 543 // Convert_v1_Volume_To_core_Volume is defined outside the autogenerated file for use by other API packages 544 func Convert_v1_Volume_To_core_Volume(in *v1.Volume, out *core.Volume, s conversion.Scope) error { 545 return autoConvert_v1_Volume_To_core_Volume(in, out, s) 546 } 547 548 // Convert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec is defined outside the autogenerated file for use by other API packages 549 func Convert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(in *core.PersistentVolumeSpec, out *v1.PersistentVolumeSpec, s conversion.Scope) error { 550 return autoConvert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(in, out, s) 551 } 552 553 // Convert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec is defined outside the autogenerated file for use by other API packages 554 func Convert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(in *v1.PersistentVolumeSpec, out *core.PersistentVolumeSpec, s conversion.Scope) error { 555 return autoConvert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(in, out, s) 556 }