/* SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. * * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System; using System.Collections.Concurrent; using System.Linq; using System.Runtime.InteropServices; using OpenSearch.Stack.ArtifactsApi.Platform; using OpenSearch.Stack.ArtifactsApi.Products; using OpenSearch.Stack.ArtifactsApi.Resolvers; using SemVer; using Version = SemVer.Version; namespace OpenSearch.Stack.ArtifactsApi { public class OpenSearchVersion : Version, IComparable<string> { private readonly ConcurrentDictionary<string, Artifact> _resolved = new(); protected OpenSearchVersion(string version, ArtifactBuildState state, string buildHash = null) : base(version) { ArtifactBuildState = state; BuildHash = buildHash; } public ArtifactBuildState ArtifactBuildState { get; } private string BuildHash { get; } public int CompareTo(string other) { var v = (OpenSearchVersion)other; return CompareTo(v); } public Artifact Artifact(Product product) { var cacheKey = product.ToString(); if (_resolved.TryGetValue(cacheKey, out var artifact)) return artifact; var currentPlatform = OsMonikers.CurrentPlatform(); switch (ArtifactBuildState) { case ArtifactBuildState.Released: ReleasedVersionResolver.TryResolve(product, this, currentPlatform, RuntimeInformation.OSArchitecture, out artifact); break; case ArtifactBuildState.Snapshot: SnapshotApiResolver.TryResolve(product, this, currentPlatform, null, out artifact); break; case ArtifactBuildState.BuildCandidate: StagingVersionResolver.TryResolve(product, this, BuildHash, out artifact); break; default: throw new ArgumentOutOfRangeException(nameof(ArtifactBuildState), $"{ArtifactBuildState} not expected here"); } _resolved.TryAdd(cacheKey, artifact); return artifact; } /// <summary> /// Resolves an OpenSearch version using either format '$version' or '$ServerType-$version', where version could be 'x.y.z' or 'latest' or even 'latest-x' /// </summary> public static OpenSearchVersion From(string managedVersionString) { if (managedVersionString == null) return null; var serverType = ServerType.DEFAULT; var hasServerType = Enum.GetNames(typeof(ServerType)).Any(s => managedVersionString.StartsWith(s, StringComparison.InvariantCultureIgnoreCase)); if (hasServerType) { var parts = managedVersionString.Split('-'); serverType = (ServerType)Enum.Parse(typeof(ServerType), parts[0], true); managedVersionString = string.Join("-", parts.Skip(1)); } if (managedVersionString.StartsWith("latest") && serverType == ServerType.OpenDistro) // No releases for OpenDistro after 1.13.3 - all deveploment afterwards goes to OpenSearch managedVersionString = "1.13.3"; if (managedVersionString.StartsWith("latest") && serverType == ServerType.ElasticSearch) // OpenDistro (1.13.x - another not supported) and OpenSearch both based on Elasticsearch v.7.10.2, other versions are incompatible managedVersionString = "7.10.2"; // TODO resolve `latest` and `latest-x` for OpenSearch return new OpenSearchVersion(managedVersionString, ArtifactBuildState.Released, ""); } internal static bool TryParseBuildCandidate(string passedVersion, out string version, out string gitHash) { version = null; gitHash = null; var tokens = passedVersion.Split(':'); if (tokens.Length < 2) return false; version = tokens[1].Trim(); gitHash = tokens[0].Trim(); return true; } public bool InRange(string range) { var versionRange = new Range(range); return InRange(versionRange); } public bool InRange(Range versionRange) { var satisfied = versionRange.IsSatisfied(this); if (satisfied) return true; //Semver can only match snapshot version with ranges on the same major and minor //anything else fails but we want to know e.g 1.0.0-SNAPSHOT satisfied by 1.0.0; var wholeVersion = $"{Major}.{Minor}.{Patch}"; return versionRange.IsSatisfied(wholeVersion); } public static implicit operator OpenSearchVersion(string version) => From(version); public static bool operator <(OpenSearchVersion first, string second) => first < (OpenSearchVersion)second; public static bool operator >(OpenSearchVersion first, string second) => first > (OpenSearchVersion)second; public static bool operator <(string first, OpenSearchVersion second) => (OpenSearchVersion)first < second; public static bool operator >(string first, OpenSearchVersion second) => (OpenSearchVersion)first > second; public static bool operator <=(OpenSearchVersion first, string second) => first <= (OpenSearchVersion)second; public static bool operator >=(OpenSearchVersion first, string second) => first >= (OpenSearchVersion)second; public static bool operator <=(string first, OpenSearchVersion second) => (OpenSearchVersion)first <= second; public static bool operator >=(string first, OpenSearchVersion second) => (OpenSearchVersion)first >= second; public static bool operator ==(OpenSearchVersion first, string second) => first == (OpenSearchVersion)second; public static bool operator !=(OpenSearchVersion first, string second) => first != (OpenSearchVersion)second; public static bool operator ==(string first, OpenSearchVersion second) => (OpenSearchVersion)first == second; public static bool operator !=(string first, OpenSearchVersion second) => (OpenSearchVersion)first != second; // ReSharper disable once UnusedMember.Local private bool Equals(OpenSearchVersion other) => base.Equals(other); public override bool Equals(object obj) => base.Equals(obj); public override int GetHashCode() => base.GetHashCode(); } }