bug4811: added ReleaseRepository and Release abstractions

This commit is contained in:
Axel Uhl
2020-10-19 16:54:38 +02:00
parent 4e0eaaa637
commit a4f347a9ec
12 changed files with 302 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src">
<attributes>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.sap.sailing.landscape.test</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8
@@ -0,0 +1,3 @@
eclipse.preferences.version=1
pluginProject.extensions=false
resolve.requirebundle=false
+10
View File
@@ -0,0 +1,10 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: com.sap.sailing.landscape.test
Bundle-SymbolicName: com.sap.sailing.landscape.test
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Fragment-Host: com.sap.sailing.landscape
Automatic-Module-Name: com.sap.sailing.landscape.test
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.junit
+4
View File
@@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
@@ -0,0 +1,21 @@
package com.sap.sailing.landscape.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import com.sap.sailing.landscape.ReleaseRepository;
import com.sap.sse.common.Util;
public class TestReleaseRepository {
@Test
public void testForAtLeastOneRelease() {
assertFalse(Util.isEmpty(ReleaseRepository.SAILING_RELEASE_REPOSITORY));
}
@Test
public void testForAtLeastOneMasterRelease() {
assertNotNull(ReleaseRepository.SAILING_RELEASE_REPOSITORY.getLatestMasterRelease());
}
}
@@ -0,0 +1,30 @@
package com.sap.sailing.landscape;
import java.net.MalformedURLException;
import java.net.URL;
import com.sap.sse.common.Named;
import com.sap.sse.common.TimePoint;
public interface Release extends Named {
String RELEASE_NOTES_FILE_NAME = "release-notes.txt";
String ARCHIVE_EXTENSION = ".tar.gz";
ReleaseRepository getRepository();
String getBaseName();
TimePoint getCreationDate();
default String getFolderURL() {
return getRepository().getRepositoryBase()+"/"+getName()+"/";
}
default URL getReleaseNotesURL() throws MalformedURLException {
return new URL(getFolderURL()+RELEASE_NOTES_FILE_NAME);
}
default URL getDeployableArchiveURL() throws MalformedURLException {
return new URL(getFolderURL()+getName()+ARCHIVE_EXTENSION);
}
}
@@ -0,0 +1,36 @@
package com.sap.sailing.landscape;
import com.sap.sailing.landscape.procedures.ReleaseRepositoryImpl;
/**
* Contains ready-built releases that can be used as part of the {@code INSTALL_FROM_RELEASE} directive. Iterating over
* this iterable's elements lists the {@link Release}s available.
*
* @author Axel Uhl (D043530)
*
*/
public interface ReleaseRepository extends Iterable<Release> {
ReleaseRepository SAILING_RELEASE_REPOSITORY = new ReleaseRepositoryImpl("http://releases.sapsailing.com", "build");
/**
* @return the latest build with name prefix {@link #MASTER_RELEASE_NAME_PREFIX} if such a release exists in this
* repository, or {@code null} otherwise
*/
default Release getLatestMasterRelease() {
return getLatestRelease(getMasterReleaseNamePrefix());
}
/**
* Returns the latest release with the prefix specified by the parameter.
*/
Release getLatestRelease(String releaseNamePrefix);
/**
* @return the {@link Release} with name {@code releaseName} if it exists, or {@code null} otherwise
*/
Release getRelease(String releaseName);
String getRepositoryBase();
String getMasterReleaseNamePrefix();
}
@@ -0,0 +1,44 @@
package com.sap.sailing.landscape.procedures;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.landscape.Release;
import com.sap.sailing.landscape.ReleaseRepository;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.NamedImpl;
public class ReleaseImpl extends NamedImpl implements Release {
private static final Logger logger = Logger.getLogger(ReleaseImpl.class.getName());
private static final long serialVersionUID = -225240683033821028L;
private final ReleaseRepository repository;
public ReleaseImpl(String name, ReleaseRepository repository) {
super(name);
this.repository = repository;
}
@Override
public ReleaseRepository getRepository() {
return repository;
}
@Override
public String getBaseName() {
return getName().substring(0, getName().lastIndexOf("-"));
}
@Override
public TimePoint getCreationDate() {
final String dateSubstring = getName().substring(getName().lastIndexOf("-")+1);
try {
return TimePoint.of(new SimpleDateFormat("yyyyMMddHHmm").parse(dateSubstring));
} catch (ParseException e) {
logger.log(Level.WARNING, "Error parsing release date "+dateSubstring+". Returning null instead.", e);
return null;
}
}
}
@@ -0,0 +1,89 @@
package com.sap.sailing.landscape.procedures;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sap.sailing.landscape.Release;
import com.sap.sailing.landscape.ReleaseRepository;
import com.sap.sse.common.Util;
public class ReleaseRepositoryImpl implements ReleaseRepository {
private static final Logger logger = Logger.getLogger(ReleaseRepositoryImpl.class.getName());
private final String repositoryBase;
private final String masterReleaseNamePrefix;
public ReleaseRepositoryImpl(String repositoryBase, String masterReleaseNamePrefix) {
super();
this.repositoryBase = repositoryBase;
this.masterReleaseNamePrefix = masterReleaseNamePrefix;
}
@Override
public String getRepositoryBase() {
return repositoryBase;
}
@Override
public String getMasterReleaseNamePrefix() {
return masterReleaseNamePrefix;
}
private Iterable<Release> getAvailableReleases() {
final List<Release> result = new LinkedList<>();
try {
final InputStream index = (InputStream) new URL(getRepositoryBase()).getContent();
int read = 0;
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((read=index.read()) != -1) {
bos.write(read);
}
index.close();
final String contents = bos.toString();
final Pattern pattern = Pattern.compile("<a href=\"(([^/]*)-([0-9]*))/\">([^/]*)-([0-9]*)/</a>");
final Matcher m = pattern.matcher(contents);
int lastMatch = 0;
while (m.find(lastMatch)) {
result.add(new ReleaseImpl(m.group(1), this));
lastMatch = m.end();
}
} catch (IOException e) {
logger.log(Level.SEVERE, "Error loading releases from repository at "+getRepositoryBase()+". Continuing empty.", e);
return Collections.emptyList();
}
return result;
}
@Override
public Iterator<Release> iterator() {
return getAvailableReleases().iterator();
}
@Override
public Release getLatestRelease(String releaseNamePrefix) {
Release result = null;
for (final Release release : getAvailableReleases()) {
if (release.getBaseName().equals(releaseNamePrefix) &&
(result == null || release.getCreationDate().after(result.getCreationDate()))) {
result = release;
}
}
return result;
}
@Override
public Release getRelease(String releaseName) {
return Util.first(Util.filter(getAvailableReleases(), r->r.getName().equals(releaseName)));
}
}
@@ -4,6 +4,8 @@ import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Optional;
import com.sap.sailing.landscape.Release;
import com.sap.sailing.landscape.ReleaseRepository;
import com.sap.sailing.landscape.SailingAnalyticsHost;
import com.sap.sailing.landscape.SailingAnalyticsMaster;
import com.sap.sailing.landscape.SailingAnalyticsMetrics;
@@ -23,6 +25,12 @@ public abstract class StartSailingAnalyticsHost<ShardingKey,
HostT extends SailingAnalyticsHost<ShardingKey>>
extends StartAwsHost<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaster<ShardingKey>, SailingAnalyticsReplica<ShardingKey>, SailingAnalyticsHost<ShardingKey>>
implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaster<ShardingKey>, SailingAnalyticsReplica<ShardingKey>> {
/**
* The user data variable to use to specify the release to install and run on the host. See also
* {@link ReleaseRepository} and {@link #getReleaseUserData}.
*/
private final static String INSTALL_FROM_RELEASE = "INSTALL_FROM_RELEASE";
private final Database databaseConfiguration;
public StartSailingAnalyticsHost(String name, MachineImage<SailingAnalyticsHost<ShardingKey>> machineImage,
@@ -34,6 +42,16 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
this.databaseConfiguration = databaseConfiguration;
addUserData(getDatabaseUserData());
}
/**
* To launch the instance with a specific release, pass the result of this method as a {@code userData} string to
* the
* {@link #StartSailingAnalyticsHost(String, MachineImage, Landscape, InstanceType, AwsAvailabilityZone, String, Iterable, Optional, Database, String...)
* constructor}.
*/
public static String getReleaseUserData(Release release) {
return INSTALL_FROM_RELEASE+"="+release.getName();
}
private Iterable<String> getDatabaseUserData() throws URISyntaxException {
return Collections.singleton(databaseConfiguration.getConnectionURI().toString());