|
18 | 18 | import io.fabric8.kubernetes.api.model.ContainerBuilder;
|
19 | 19 | import io.fabric8.kubernetes.api.model.EnvFromSource;
|
20 | 20 | import io.fabric8.kubernetes.api.model.EnvVar;
|
21 |
| -import io.fabric8.kubernetes.api.model.KeyToPath; |
22 | 21 | import io.fabric8.kubernetes.api.model.LocalObjectReference;
|
23 | 22 | import io.fabric8.kubernetes.api.model.ObjectMeta;
|
24 | 23 | import io.fabric8.kubernetes.api.model.Pod;
|
|
29 | 28 | import io.fabric8.kubernetes.api.model.Toleration;
|
30 | 29 | import io.fabric8.kubernetes.api.model.Volume;
|
31 | 30 | import io.fabric8.kubernetes.api.model.VolumeMount;
|
32 |
| -import io.fabric8.kubernetes.client.KubernetesClient; |
33 |
| -import io.fabric8.kubernetes.client.KubernetesClientBuilder; |
34 |
| -import io.fabric8.kubernetes.client.KubernetesClientException; |
35 |
| -import io.fabric8.kubernetes.client.utils.Serialization; |
36 | 31 | import java.io.ByteArrayInputStream;
|
37 | 32 | import java.io.IOException;
|
38 | 33 | import java.io.InputStream;
|
@@ -70,14 +65,6 @@ public class PodTemplateUtils {
|
70 | 65 | @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "tests & emergency admin")
|
71 | 66 | public static boolean SUBSTITUTE_ENV = Boolean.getBoolean(PodTemplateUtils.class.getName() + ".SUBSTITUTE_ENV");
|
72 | 67 |
|
73 |
| - /** |
74 |
| - * If true, all modes permissions provided to pods are expected to be provided in decimal notation. |
75 |
| - * Otherwise, the plugin will consider they are written in octal notation. |
76 |
| - */ |
77 |
| - @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "tests & emergency admin") |
78 |
| - public static /* almost final*/ boolean DISABLE_OCTAL_MODES = |
79 |
| - Boolean.getBoolean(PodTemplateUtils.class.getName() + ".DISABLE_OCTAL_MODES"); |
80 |
| - |
81 | 68 | /**
|
82 | 69 | * Combines a {@link ContainerTemplate} with its parent.
|
83 | 70 | * @param parent The parent container template (nullable).
|
@@ -287,8 +274,8 @@ public static Pod combine(Pod parent, Pod template) {
|
287 | 274 | return template;
|
288 | 275 | }
|
289 | 276 |
|
290 |
| - LOGGER.finest(() -> "Combining pods, parent: " + Serialization.asYaml(parent) + " template: " |
291 |
| - + Serialization.asYaml(template)); |
| 277 | + LOGGER.finest(() -> "Combining pods, parent: " + Serialization2.asYaml(parent) + " template: " |
| 278 | + + Serialization2.asYaml(template)); |
292 | 279 |
|
293 | 280 | Map<String, String> nodeSelector =
|
294 | 281 | mergeMaps(parent.getSpec().getNodeSelector(), template.getSpec().getNodeSelector());
|
@@ -412,7 +399,7 @@ public static Pod combine(Pod parent, Pod template) {
|
412 | 399 | // podTemplate.setYaml(template.getYaml() == null ? parent.getYaml() : template.getYaml());
|
413 | 400 |
|
414 | 401 | Pod pod = specBuilder.endSpec().build();
|
415 |
| - LOGGER.finest(() -> "Pods combined: " + Serialization.asYaml(pod)); |
| 402 | + LOGGER.finest(() -> "Pods combined: " + Serialization2.asYaml(pod)); |
416 | 403 | return pod;
|
417 | 404 | }
|
418 | 405 |
|
@@ -699,102 +686,27 @@ public static String substitute(String s, Map<String, String> properties, String
|
699 | 686 |
|
700 | 687 | public static Pod parseFromYaml(String yaml) {
|
701 | 688 | String s = yaml;
|
702 |
| - try (KubernetesClient client = new KubernetesClientBuilder().build()) { |
703 |
| - // JENKINS-57116 |
704 |
| - if (StringUtils.isBlank(s)) { |
705 |
| - LOGGER.log(Level.WARNING, "[JENKINS-57116] Trying to parse invalid yaml: \"{0}\"", yaml); |
706 |
| - s = "{}"; |
707 |
| - } |
708 |
| - Pod podFromYaml; |
709 |
| - try (InputStream is = new ByteArrayInputStream(s.getBytes(UTF_8))) { |
710 |
| - podFromYaml = client.pods().load(is).item(); |
711 |
| - } catch (IOException | KubernetesClientException e) { |
712 |
| - throw new RuntimeException(String.format("Failed to parse yaml: \"%s\"", yaml), e); |
713 |
| - } |
714 |
| - LOGGER.finest(() -> "Parsed pod template from yaml: " + Serialization.asYaml(podFromYaml)); |
715 |
| - // yaml can be just a fragment, avoid NPEs |
716 |
| - if (podFromYaml.getMetadata() == null) { |
717 |
| - podFromYaml.setMetadata(new ObjectMeta()); |
718 |
| - } |
719 |
| - if (podFromYaml.getSpec() == null) { |
720 |
| - podFromYaml.setSpec(new PodSpec()); |
721 |
| - } |
722 |
| - if (!DISABLE_OCTAL_MODES) { |
723 |
| - fixOctal(podFromYaml); |
724 |
| - } |
725 |
| - return podFromYaml; |
| 689 | + // JENKINS-57116 |
| 690 | + if (StringUtils.isBlank(s)) { |
| 691 | + LOGGER.log(Level.WARNING, "[JENKINS-57116] Trying to parse invalid yaml: \"{0}\"", yaml); |
| 692 | + s = "{}"; |
726 | 693 | }
|
727 |
| - } |
728 |
| - |
729 |
| - private static void fixOctal(@NonNull Pod podFromYaml) { |
730 |
| - podFromYaml.getSpec().getVolumes().stream().map(Volume::getConfigMap).forEach(configMap -> { |
731 |
| - if (configMap != null) { |
732 |
| - var defaultMode = configMap.getDefaultMode(); |
733 |
| - if (defaultMode != null) { |
734 |
| - configMap.setDefaultMode(convertPermissionToOctal(defaultMode)); |
735 |
| - } |
736 |
| - } |
737 |
| - }); |
738 |
| - podFromYaml.getSpec().getVolumes().stream().map(Volume::getSecret).forEach(secretVolumeSource -> { |
739 |
| - if (secretVolumeSource != null) { |
740 |
| - var defaultMode = secretVolumeSource.getDefaultMode(); |
741 |
| - if (defaultMode != null) { |
742 |
| - secretVolumeSource.setDefaultMode(convertPermissionToOctal(defaultMode)); |
743 |
| - } |
744 |
| - } |
745 |
| - }); |
746 |
| - podFromYaml.getSpec().getVolumes().stream().map(Volume::getProjected).forEach(projected -> { |
747 |
| - if (projected != null) { |
748 |
| - var defaultMode = projected.getDefaultMode(); |
749 |
| - if (defaultMode != null) { |
750 |
| - projected.setDefaultMode(convertPermissionToOctal(defaultMode)); |
751 |
| - } |
752 |
| - projected.getSources().forEach(source -> { |
753 |
| - var configMap = source.getConfigMap(); |
754 |
| - if (configMap != null) { |
755 |
| - convertDecimalIntegersToOctal(configMap.getItems()); |
756 |
| - } |
757 |
| - var secret = source.getSecret(); |
758 |
| - if (secret != null) { |
759 |
| - convertDecimalIntegersToOctal(secret.getItems()); |
760 |
| - } |
761 |
| - }); |
762 |
| - } |
763 |
| - }); |
764 |
| - } |
765 |
| - |
766 |
| - private static void convertDecimalIntegersToOctal(List<KeyToPath> items) { |
767 |
| - items.forEach(i -> { |
768 |
| - var mode = i.getMode(); |
769 |
| - if (mode != null) { |
770 |
| - i.setMode(convertPermissionToOctal(mode)); |
771 |
| - } |
772 |
| - }); |
773 |
| - } |
774 |
| - |
775 |
| - /** |
776 |
| - * Permissions are generally expressed in octal notation, e.g. 0777. |
777 |
| - * After parsing, this is stored as the integer 777, but the snakeyaml-engine does not convert to decimal first. |
778 |
| - * When the client later sends the pod spec to the server, it sends the integer as is through the json schema, |
779 |
| - * however the server expects a decimal, which means an integer between 0 and 511. |
780 |
| - * |
781 |
| - * The user can also provide permissions as a decimal integer, e.g. 511. |
782 |
| - * |
783 |
| - * This method attempts to guess whether the user provided a decimal or octal integer, and converts to octal if needed, |
784 |
| - * so that the resulting can be submitted to the server. |
785 |
| - * |
786 |
| - */ |
787 |
| - static int convertPermissionToOctal(Integer i) { |
788 |
| - // Permissions are expressed as octal integers |
789 |
| - // octal goes from 0000 to 0777 |
790 |
| - // decimal goes from 0 to 511 |
791 |
| - var s = Integer.toString(i, 10); |
792 |
| - // If the input has a digit which is 8 or 9, this was likely a decimal input. Best effort support here. |
793 |
| - if (s.chars().map(c -> c - '0').anyMatch(a -> a > 7)) { |
794 |
| - return i; |
795 |
| - } else { |
796 |
| - return Integer.parseInt(s, 8); |
| 694 | + Pod podFromYaml; |
| 695 | + try (InputStream is = new ByteArrayInputStream(s.getBytes(UTF_8))) { |
| 696 | + podFromYaml = Serialization2.unmarshal(is, Pod.class); |
| 697 | + // podFromYaml = new KubernetesSerialization().unmarshal(is, Pod.class); |
| 698 | + } catch (IOException e) { |
| 699 | + throw new RuntimeException(String.format("Failed to parse yaml: \"%s\"", yaml), e); |
| 700 | + } |
| 701 | + LOGGER.finest(() -> "Parsed pod template from yaml: " + Serialization2.asYaml(podFromYaml)); |
| 702 | + // yaml can be just a fragment, avoid NPEs |
| 703 | + if (podFromYaml.getMetadata() == null) { |
| 704 | + podFromYaml.setMetadata(new ObjectMeta()); |
| 705 | + } |
| 706 | + if (podFromYaml.getSpec() == null) { |
| 707 | + podFromYaml.setSpec(new PodSpec()); |
797 | 708 | }
|
| 709 | + return podFromYaml; |
798 | 710 | }
|
799 | 711 |
|
800 | 712 | public static Collection<String> validateYamlContainerNames(List<String> yamls) {
|
|
0 commit comments