Pārlūkot izejas kodu

move software version management into its own class

tags/v1.1.4
Jonathan Cobb pirms 4 gadiem
vecāks
revīzija
31640c0c43
4 mainītis faili ar 157 papildinājumiem un 132 dzēšanām
  1. +2
    -25
      bubble-server/src/main/java/bubble/server/BubbleConfiguration.java
  2. +141
    -0
      bubble-server/src/main/java/bubble/server/SoftwareVersions.java
  3. +8
    -46
      bubble-server/src/main/java/bubble/service/packer/PackerJob.java
  4. +6
    -61
      bubble-server/src/main/java/bubble/service/packer/PackerService.java

+ 2
- 25
bubble-server/src/main/java/bubble/server/BubbleConfiguration.java Parādīt failu

@@ -168,30 +168,7 @@ public class BubbleConfiguration extends PgRestServerConfiguration
@Getter @Setter private String letsencryptEmail;

@Getter @Setter private String releaseUrlBase;

public static final File SOFTWARE_VERSIONS_FILE = new File(HOME_DIR+"/bubble_versions.properties");
@Getter(lazy=true) private final Properties defaultSoftwareVersions = initDefaultSoftwareVersions();
private Properties initDefaultSoftwareVersions() {
if (!SOFTWARE_VERSIONS_FILE.exists()) return null;
final Properties props = new Properties();
try (InputStream in = new FileInputStream(SOFTWARE_VERSIONS_FILE)) {
props.load(in);
return props;
} catch (Exception e) {
log.error("initDefaultSoftwareVersions: "+shortError(e));
return null;
}
}

public void saveSoftwareVersions (Properties softwareVersions) {
if (!SOFTWARE_VERSIONS_FILE.exists()) {
try (OutputStream out = new FileOutputStream(SOFTWARE_VERSIONS_FILE)) {
softwareVersions.store(out, null);
} catch (Exception e) {
log.error("saveSoftwareVersions: "+shortError(e));
}
}
}
@Getter(lazy=true) private final SoftwareVersions softwareVersions = new SoftwareVersions(getReleaseUrlBase());

@Setter private String localStorageDir = DEFAULT_LOCAL_STORAGE_DIR;
public String getLocalStorageDir () { return empty(localStorageDir) ? DEFAULT_LOCAL_STORAGE_DIR : localStorageDir; }
@@ -292,7 +269,7 @@ public class BubbleConfiguration extends PgRestServerConfiguration
.setVersion(version)
.setShortVersion(shortVersion)
.setSha256(getJarSha())
.setSoftware(getDefaultSoftwareVersions());
.setSoftware(getSoftwareVersions().getDefaultSoftwareVersions());
}
public String getShortVersion () { return getVersionInfo().getShortVersion(); }



+ 141
- 0
bubble-server/src/main/java/bubble/server/SoftwareVersions.java Parādīt failu

@@ -0,0 +1,141 @@
/**
* Copyright (c) 2020 Bubble, Inc. All rights reserved.
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/
*/
package bubble.server;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.io.FileUtil;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import static bubble.ApiConstants.HOME_DIR;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.http.HttpUtil.url2string;

@Slf4j
public class SoftwareVersions {

public static final String ROLE_ALGO = "algo";
public static final String ROLE_MITMPROXY = "mitmproxy";
public static final String ROLE_DNSCRYPT = "dnscrypt-proxy";
public static final String ROLE_BUBBLE = "bubble";
public static final String[] VERSIONED_SOFTWARE = {ROLE_DNSCRYPT, ROLE_ALGO, ROLE_MITMPROXY};

public static final File SOFTWARE_VERSIONS_FILE = new File(HOME_DIR+"/bubble_versions.properties");

public static final String SUFFIX_VERSION = "_version";
public static final String SUFFIX_SHA = "_sha";

private final String releaseUrlBase;

public SoftwareVersions (String releaseUrlBase) { this.releaseUrlBase = releaseUrlBase; }

public String getRolePropBase(String roleName) { return roleName.replace("-", "_"); }

public String getLatestVersion(String r) {
try {
return url2string(releaseUrlBase+"/"+ r +"/latest.txt").trim();
} catch (IOException e) {
return die("getLatestVersion("+ r +"): "+shortError(e), e);
}
}

public String downloadHash(String roleName, String version) {
try {
return url2string(releaseUrlBase+"/"+ roleName +"/"+ version +"/"+ roleName +getSoftwareSuffix(roleName)+".sha256").trim();
} catch (IOException e) {
return die("getSoftwareHash("+ roleName +"): "+shortError(e), e);
}
}

@Getter(lazy=true) private final Properties defaultSoftwareVersions = initDefaultSoftwareVersions();
private Properties initDefaultSoftwareVersions() {
if (empty(releaseUrlBase)) {
log.warn("initDefaultSoftwareVersions: releaseUrlBase not defined");
return null;
}
final Properties props = new Properties();
if (!SOFTWARE_VERSIONS_FILE.exists()) {
// write latest versions
for (String roleName : VERSIONED_SOFTWARE) {
final String latestVersion = getLatestVersion(roleName);
props.setProperty(getRolePropBase(roleName)+SUFFIX_VERSION, latestVersion);
props.setProperty(getRolePropBase(roleName)+SUFFIX_SHA, downloadHash(roleName, latestVersion));
}
writeVersions(props, SOFTWARE_VERSIONS_FILE);
}
try (InputStream in = new FileInputStream(SOFTWARE_VERSIONS_FILE)) {
props.load(in);
return props;
} catch (Exception e) {
log.error("initDefaultSoftwareVersions: "+shortError(e));
return null;
}
}

public void writeVersions(File file) { writeVersions(getDefaultSoftwareVersions(), file); }

public void writeVersions(Properties props, File file) {
try (OutputStream out = new FileOutputStream(file)) {
props.store(out, null);
} catch (Exception e) {
log.error("saveSoftwareVersions: "+shortError(e));
}
}

public void writeAnsibleVars(File file) { writeAnsibleVars(getDefaultSoftwareVersions(), file); }

public void writeAnsibleVars(Properties props, File file) {
try (OutputStream out = new FileOutputStream(file)) {
final StringBuilder b = new StringBuilder();
for (String name : props.stringPropertyNames()) {
b.append(name).append(" : '").append(props.getProperty(name)).append("'\n");
}
FileUtil.toFile(file, b.toString());

} catch (Exception e) {
die("writeAnsibleVars: "+shortError(e));
}
}

private final Map<String, String> softwareVersions = new HashMap<>();

public String getSoftwareVersion(String roleName) {
final Properties defaults = getDefaultSoftwareVersions();
if (defaults != null) {
final String propName = getRolePropBase(roleName) + SUFFIX_VERSION;
final String version = defaults.getProperty(propName);
if (version != null) return version;
}
return softwareVersions.computeIfAbsent(roleName, this::getLatestVersion);
}

private final Map<String, String> softwareHashes = new HashMap<>();

public String getSoftwareHash(String roleName, String version) {
final Properties defaults = getDefaultSoftwareVersions();
if (defaults != null) {
final String roleBase = getRolePropBase(roleName);
final String foundVersion = defaults.getProperty(roleBase + SUFFIX_VERSION);
if (foundVersion != null && foundVersion.equals(version)) {
final String hash = defaults.getProperty(roleBase + SUFFIX_SHA);
if (hash != null) return hash;
}
}
return softwareHashes.computeIfAbsent(roleName, r -> downloadHash(r, version));
}

private String getSoftwareSuffix(String roleName) {
switch (roleName) {
case ROLE_ALGO: case ROLE_MITMPROXY: return ".zip";
case ROLE_DNSCRYPT: return "";
default: return die("getSoftwareSuffix: unrecognized roleName: "+roleName);
}
}

}

+ 8
- 46
bubble-server/src/main/java/bubble/service/packer/PackerJob.java Parādīt failu

@@ -16,6 +16,7 @@ import bubble.model.account.Account;
import bubble.model.cloud.AnsibleInstallType;
import bubble.model.cloud.CloudService;
import bubble.server.BubbleConfiguration;
import bubble.server.SoftwareVersions;
import bubble.service.cloud.GeoService;
import lombok.Cleanup;
import lombok.Getter;
@@ -41,9 +42,9 @@ import java.util.stream.Collectors;

import static bubble.ApiConstants.copyScripts;
import static bubble.model.cloud.RegionalServiceDriver.findClosestRegions;
import static bubble.server.SoftwareVersions.*;
import static bubble.service.packer.PackerService.*;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.http.HttpUtil.url2string;
import static org.cobbzilla.util.io.FileUtil.*;
import static org.cobbzilla.util.io.StreamUtil.copyClasspathDirectory;
import static org.cobbzilla.util.io.StreamUtil.stream2string;
@@ -160,12 +161,9 @@ public class PackerJob implements Callable<List<PackerImage>> {
@Cleanup final TempDir tempDir = copyClasspathDirectory("packer");

// record versions of algo, mitmproxy and dnscrypt_proxy
final Map<String, String> versions = new HashMap<>();
versions.putAll(getSoftwareVersion(ROLE_ALGO, tempDir));
versions.putAll(getSoftwareVersion(ROLE_MITMPROXY, tempDir));

// write versions to bubble vars
writeBubbleVersions(tempDir, versions);
writeSoftwareVars(ROLE_ALGO, tempDir);
writeSoftwareVars(ROLE_MITMPROXY, tempDir);
writeSoftwareVars(ROLE_BUBBLE, tempDir);

// copy packer ssh key
copyFile(packerService.getPackerPublicKey(), new File(abs(tempDir)+"/roles/common/files/"+PACKER_KEY_NAME));
@@ -292,46 +290,10 @@ public class PackerJob implements Callable<List<PackerImage>> {
return images;
}

private void writeBubbleVersions(TempDir tempDir, Map<String, String> versions) {
final File varsDir = mkdirOrDie(abs(tempDir) + "/roles/"+ROLE_BUBBLE+"/vars");
final StringBuilder b = new StringBuilder();
final Properties softwareProps = new Properties();
for (Map.Entry<String, String> var : versions.entrySet()) {
final String roleName = var.getKey();
final String version = var.getValue().trim();
final String roleBase = roleName.replace("-", "_");
final String hash = packerService.getSoftwareHash(roleName, version);
b.append(roleBase).append("_version : '").append(version).append("'\n")
.append(roleBase).append("_sha : '").append(hash).append("'\n");
softwareProps.setProperty(roleBase+"_version", version);
softwareProps.setProperty(roleBase+"_sha", hash);
}
FileUtil.toFileOrDie(new File(varsDir, "main.yml"), b.toString());
configuration.saveSoftwareVersions(softwareProps);
}

private Map<String, String> getSoftwareVersion(String roleName, TempDir tempDir) throws IOException {
final Map<String, String> vars = new HashMap<>();
final String releaseUrlBase = configuration.getReleaseUrlBase();
private void writeSoftwareVars(String roleName, TempDir tempDir) throws IOException {
final SoftwareVersions softwareVersions = configuration.getSoftwareVersions();
final File varsDir = mkdirOrDie(abs(tempDir) + "/roles/"+roleName+"/vars");

// determine latest version
final String version = packerService.getSoftwareVersion(roleName);
vars.put(roleName, version);

final String hash = packerService.getSoftwareHash(roleName, version);
String varsData = roleName+"_sha : '"+hash+"'\n"
+ roleName+"_version : '" + version + "'\n";

if (roleName.equals(ROLE_ALGO)) {
// capture dnscrypt_proxy version for algo
final String dnscryptVersion = url2string(releaseUrlBase+"/"+roleName+"/"+version+"/dnscrypt-proxy_version.txt").trim();
varsData += "dnscrypt_proxy_version : '"+dnscryptVersion+"'\n"
+ "dnscrypt_proxy_sha : '"+packerService.getSoftwareHash(ROLE_DNSCRYPT, dnscryptVersion)+"'";
vars.put(ROLE_DNSCRYPT, dnscryptVersion);
}
FileUtil.toFileOrDie(new File(varsDir, "main.yml"), varsData);
return vars;
softwareVersions.writeAnsibleVars(new File(varsDir, "main.yml"));
}

private List<String> getRolesForInstallType(AnsibleInstallType installType) {


+ 6
- 61
bubble-server/src/main/java/bubble/service/packer/PackerService.java Parādīt failu

@@ -8,24 +8,22 @@ import bubble.cloud.compute.PackerImage;
import bubble.model.cloud.AnsibleInstallType;
import bubble.model.cloud.CloudService;
import bubble.server.BubbleConfiguration;
import bubble.server.SoftwareVersions;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.daemon.DaemonThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static bubble.server.SoftwareVersions.*;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.http.HttpUtil.url2string;
import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.io.FileUtil.mkdirOrDie;
import static org.cobbzilla.util.io.StreamUtil.stream2string;
@@ -45,11 +43,6 @@ public class PackerService {
public static final List<String> NODE_ROLES = splitAndTrim(stream2string(PACKER_DIR + "/node-roles.txt"), "\n")
.stream().filter(s -> !empty(s)).collect(Collectors.toList());

public static final String ROLE_ALGO = "algo";
public static final String ROLE_MITMPROXY = "mitmproxy";
public static final String ROLE_DNSCRYPT = "dnscrypt-proxy";
public static final String ROLE_BUBBLE = "bubble";

public static final String PACKER_KEY_NAME = "packer_rsa";

private final Map<String, PackerJob> activeJobs = new ConcurrentHashMap<>(16);
@@ -95,11 +88,12 @@ public class PackerService {
public String getPackerPublicKeyHash () { return sha256_file(getPackerPublicKey()); }

public String getPackerVersionHash () {
final SoftwareVersions softwareVersions = configuration.getSoftwareVersions();
final String keyHash = getPackerPublicKeyHash();
final String versions = ""
+"_d"+getSoftwareVersion(ROLE_DNSCRYPT)
+"_a"+getSoftwareVersion(ROLE_ALGO)
+"_m"+getSoftwareVersion(ROLE_MITMPROXY);
+"_d"+softwareVersions.getSoftwareVersion(ROLE_DNSCRYPT)
+"_a"+softwareVersions.getSoftwareVersion(ROLE_ALGO)
+"_m"+softwareVersions.getSoftwareVersion(ROLE_MITMPROXY);
if (versions.length() > 48) return die("getPackerVersionHash: software versions are too long (versions.length == "+versions.length()+" > 48): "+versions);
return keyHash.substring(64 - versions.length())+versions;
}
@@ -118,53 +112,4 @@ public class PackerService {
return pub ? pubKeyFile : privateKeyFile;
}

private final Map<String, String> softwareVersions = new HashMap<>();

public String getSoftwareVersion(String roleName) {
final Properties defaults = configuration.getDefaultSoftwareVersions();
if (defaults != null) {
final String propName = roleName.replace("-", "_")+"_version";
final String version = defaults.getProperty(propName);
if (version != null) return version;
}
final String releaseUrlBase = configuration.getReleaseUrlBase();
return softwareVersions.computeIfAbsent(roleName, r -> {
try {
return url2string(releaseUrlBase+"/"+r+"/latest.txt").trim();
} catch (IOException e) {
return die("getSoftwareVersion("+r+"): "+shortError(e), e);
}
});
}

private final Map<String, String> softwareHashes = new HashMap<>();

public String getSoftwareHash(String roleName, String version) {
final Properties defaults = configuration.getDefaultSoftwareVersions();
if (defaults != null) {
final String roleBase = roleName.replace("-", "_");
final String foundVersion = defaults.getProperty(roleBase +"_version");
if (foundVersion != null && foundVersion.equals(version)) {
final String hash = defaults.getProperty(roleBase +"_sha");
if (hash != null) return hash;
}
}
final String releaseUrlBase = configuration.getReleaseUrlBase();
return softwareHashes.computeIfAbsent(roleName, r -> {
try {
return url2string(releaseUrlBase+"/"+roleName+"/"+version+"/"+roleName+getSoftwareSuffix(roleName)+".sha256").trim();
} catch (IOException e) {
return die("getSoftwareHash("+r+"): "+shortError(e), e);
}
});
}

private String getSoftwareSuffix(String roleName) {
switch (roleName) {
case ROLE_ALGO: case ROLE_MITMPROXY: return ".zip";
case ROLE_DNSCRYPT: return "";
default: return die("getSoftwareSuffix: unrecognized roleName: "+roleName);
}
}

}

Notiek ielāde…
Atcelt
Saglabāt