/// <summary> /// Builds a <see cref="GkePlatformDetails"/> from the given metadata and kubernetes data. /// The metadata is normally retrieved from the GCE metadata server. /// The kubernetes data is normally retrieved using the kubernetes API. /// This method attempts to return as much information as it is present on <paramref name="metadataJson"/> /// and <paramref name="kubernetesData"/> but will return <see cref="string.Empty"/> for <see cref="GkePlatformDetails"/> /// properties whose corresponding information is corrupt or missing in <paramref name="metadataJson"/> /// or <paramref name="kubernetesData"/>. /// </summary> /// <param name="metadataJson">JSON metadata, normally retrieved from the GCE metadata server. /// Must not be <c>null</c>.</param> /// <param name="kubernetesData">Kubernetes data, normally retrieved using the kubernetes API. /// Must not be <c>null</c>.</param> /// <returns>A populated <see cref="GkePlatformDetails"/> if the metadata represents and GKE instance; /// <c>null</c> otherwise.</returns> public static GkePlatformDetails TryLoad(string metadataJson, KubernetesData kubernetesData) { GaxPreconditions.CheckNotNull(metadataJson, nameof(metadataJson)); GaxPreconditions.CheckNotNull(kubernetesData, nameof(kubernetesData)); JObject metadata = null; JObject namespaceData = null; JObject podData = null; // Parse JSON, ignoring all errors; partially available data is supported try { metadata = JObject.Parse(metadataJson); } catch { } try { namespaceData = JObject.Parse(kubernetesData.NamespaceJson); } catch { } try { podData = JObject.Parse(kubernetesData.PodJson); } catch { } if (metadata == null) { // Metadata is required. If it's not present, or the JSON cannot be parsed, return null. return(null); } if (namespaceData?["kind"]?.Value <string>() != "Namespace") { // If namespaceData looks corrupt/incomplete, ignore it. namespaceData = null; } if (podData?["kind"]?.Value <string>() != "Pod") { // If podData looks corrupt/incomplete, ignore it. podData = null; } var hostName = kubernetesData.PodName ?? podData?["metadata"]?["name"]?.Value <string>() ?? ""; // Pod name is the hostname var projectId = metadata["project"]?["projectId"]?.Value <string>(); var clusterName = metadata["instance"]?["attributes"]?["cluster-name"]?.Value <string>(); var instanceId = metadata["instance"]?["id"]?.Value <string>(); var instanceZone = metadata["instance"]?["zone"]?.Value <string>(); var clusterLocation = metadata["instance"]?["attributes"]?["cluster-location"]?.Value <string>(); var namespaceId = namespaceData?["metadata"]?["name"]?.Value <string>() ?? kubernetesData.NamespaceName ?? ""; var podId = podData?["metadata"]?["name"]?.Value <string>() ?? kubernetesData.PodName ?? ""; var podUid = podData?["metadata"]?["uid"]?.Value <string>() ?? ""; // A hack to find the container name. There appears to be no official way to do this. var regex = new Regex($"/var/lib/kubelet/pods/{podUid}/containers/([^/]+)/.*/dev/termination-log"); var containerNames = kubernetesData.MountInfo?.Select(x => { var match = regex.Match(x); if (match.Success) { return(match.Groups[1].Value); } return(null); }).Where(x => x != null).ToList(); var containerName = containerNames?.Count == 1 ? containerNames[0] : ""; if (hostName != null && projectId != null && clusterName != null && instanceId != null && instanceZone != null && clusterLocation != null && namespaceId != null && podId != null && containerName != null) { if (Platform.s_zoneTemplate.TryParseName(instanceZone, out var instanceLocation)) { return(new GkePlatformDetails(metadataJson, projectId, clusterName, instanceLocation[1], hostName, instanceId, instanceZone, namespaceId, podId, containerName, clusterLocation)); } } return(null); }
private IKubernetes GetKubernetesClient(KubernetesData kubernetesData) { if (kubernetesData is null) { throw new ArgumentNullException(nameof(kubernetesData)); } var kubernetesConfig = Yaml.LoadFromString <K8SConfiguration>(kubernetesData.Yaml); return(GetKubernetesClient(kubernetesConfig)); }
/// <summary> /// Builds a <see cref="GkePlatformDetails"/> from the given metadata and kubernetes data. /// The metadata is normally retrieved from the GCE metadata server. /// The kubernetes data is normally retrieved using the kubernetes API. /// This method attempts to return as much information as it is present on <paramref name="metadataJson"/> /// and <paramref name="kubernetesData"/> but will return <see cref="string.Empty"/> for <see cref="GkePlatformDetails"/> /// properties whose corresponding information is corrupt or missing in <paramref name="metadataJson"/> /// or <paramref name="kubernetesData"/>. /// </summary> /// <param name="metadataJson">JSON metadata, normally retrieved from the GCE metadata server. /// Must not be <c>null</c>.</param> /// <param name="kubernetesData">Kubernetes data, normally retrieved using the kubernetes API. /// Must not be <c>null</c>.</param> /// <returns>A populated <see cref="GkePlatformDetails"/> if the metadata represents and GKE instance; /// <c>null</c> otherwise.</returns> public static GkePlatformDetails TryLoad(string metadataJson, KubernetesData kubernetesData) { GaxPreconditions.CheckNotNull(metadataJson, nameof(metadataJson)); GaxPreconditions.CheckNotNull(kubernetesData, nameof(kubernetesData)); JObject metadata = null; JObject namespaceData = null; JObject podData = null; // Parse JSON, ignoring all errors; partially available data is supported try { metadata = JObject.Parse(metadataJson); } catch { } try { namespaceData = JObject.Parse(kubernetesData.NamespaceJson); } catch { } try { podData = JObject.Parse(kubernetesData.PodJson); } catch { } if (metadata == null) { // Metadata is required. If it's not present, or the JSON cannot be parsed, return null. return(null); } if (namespaceData?["kind"]?.Value <string>() != "Namespace") { // If namespaceData looks corrupt/incomplete, ignore it. namespaceData = null; } if (podData?["kind"]?.Value <string>() != "Pod") { // If podData looks corrupt/incomplete, ignore it. podData = null; } var hostName = kubernetesData.PodName ?? podData?["metadata"]?["name"]?.Value <string>() ?? ""; // Pod name is the hostname var projectId = metadata["project"]?["projectId"]?.Value <string>(); var clusterName = metadata["instance"]?["attributes"]?["cluster-name"]?.Value <string>(); var instanceId = metadata["instance"]?["id"]?.Value <string>(); var instanceZone = metadata["instance"]?["zone"]?.Value <string>(); var clusterLocation = metadata["instance"]?["attributes"]?["cluster-location"]?.Value <string>(); var namespaceId = namespaceData?["metadata"]?["name"]?.Value <string>() ?? kubernetesData.NamespaceName ?? ""; var podId = podData?["metadata"]?["name"]?.Value <string>() ?? kubernetesData.PodName ?? ""; // Note: unlike other variables, we keep null as null here - we're not propagating it anywhere beyond the DeriveContainerName method. var podUid = podData?["metadata"]?["uid"]?.Value <string>(); var containerName = DeriveContainerName(podUid, kubernetesData.MountInfo) ?? ""; if (hostName != null && projectId != null && clusterName != null && instanceId != null && instanceZone != null && clusterLocation != null && namespaceId != null && podId != null && containerName != null) { if (Platform.s_zoneTemplate.TryParseName(instanceZone, out var instanceLocation)) { return(new GkePlatformDetails(metadataJson, projectId, clusterName, instanceLocation[1], hostName, instanceId, instanceZone, namespaceId, podId, containerName, clusterLocation)); } } return(null); }