diff --git a/pom.xml b/pom.xml index ce3621de0a..0b9eb5ed5f 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ - 1.1.6 + 1.1.7 4.7.2 diff --git a/server-core/pom.xml b/server-core/pom.xml index bd349ee199..4e9c105e18 100644 --- a/server-core/pom.xml +++ b/server-core/pom.xml @@ -388,7 +388,7 @@ io.onedev k8s-helper - 1.0.4 + 1.0.5 diff --git a/server-core/src/main/java/io/onedev/server/CoreModule.java b/server-core/src/main/java/io/onedev/server/CoreModule.java index ba64a483ce..cd662cc842 100644 --- a/server-core/src/main/java/io/onedev/server/CoreModule.java +++ b/server-core/src/main/java/io/onedev/server/CoreModule.java @@ -167,7 +167,7 @@ import io.onedev.server.maintenance.RestoreDatabase; import io.onedev.server.maintenance.Upgrade; import io.onedev.server.migration.JpaConverter; import io.onedev.server.migration.PersistentBagConverter; -import io.onedev.server.model.support.DiscoveredJobExecutor; +import io.onedev.server.model.support.AutoDiscoveredJobExecutor; import io.onedev.server.model.support.authenticator.Authenticator; import io.onedev.server.notification.CodeCommentNotificationManager; import io.onedev.server.notification.CommitNotificationManager; @@ -391,12 +391,12 @@ public class CoreModule extends AbstractPluginModule { @Override public Class getAbstractClass() { - return DiscoveredJobExecutor.class; + return AutoDiscoveredJobExecutor.class; } @Override public Collection> getImplementations() { - return Sets.newHashSet(DiscoveredJobExecutor.class); + return Sets.newHashSet(AutoDiscoveredJobExecutor.class); } }); diff --git a/server-core/src/main/java/io/onedev/server/OneDev.java b/server-core/src/main/java/io/onedev/server/OneDev.java index c14bf36f1e..11d6c48d69 100644 --- a/server-core/src/main/java/io/onedev/server/OneDev.java +++ b/server-core/src/main/java/io/onedev/server/OneDev.java @@ -33,8 +33,8 @@ import io.onedev.server.maintenance.DataManager; import io.onedev.server.persistence.PersistManager; import io.onedev.server.persistence.SessionManager; import io.onedev.server.persistence.annotation.Sessional; +import io.onedev.server.util.ServerConfig; import io.onedev.server.util.jetty.JettyRunner; -import io.onedev.server.util.serverconfig.ServerConfig; public class OneDev extends AbstractPlugin implements Serializable { @@ -127,7 +127,7 @@ public class OneDev extends AbstractPlugin implements Serializable { if (serverConfig.getHttpPort() != 0) serverUrl = "http://" + hostName + ":" + serverConfig.getHttpPort(); else - serverUrl = "https://" + hostName + ":" + serverConfig.getSslConfig().getPort(); + serverUrl = "https://" + hostName + ":" + serverConfig.getHttpsPort(); return StringUtils.stripEnd(serverUrl, "/"); } diff --git a/server-core/src/main/java/io/onedev/server/git/GitFilter.java b/server-core/src/main/java/io/onedev/server/git/GitFilter.java index 707bcf7f10..fa5f30589e 100644 --- a/server-core/src/main/java/io/onedev/server/git/GitFilter.java +++ b/server-core/src/main/java/io/onedev/server/git/GitFilter.java @@ -44,7 +44,7 @@ import io.onedev.server.persistence.annotation.Sessional; import io.onedev.server.security.CodePullAuthorizationSource; import io.onedev.server.security.SecurityUtils; import io.onedev.server.storage.StorageManager; -import io.onedev.server.util.serverconfig.ServerConfig; +import io.onedev.server.util.ServerConfig; import io.onedev.server.util.work.WorkExecutor; @Singleton @@ -128,12 +128,12 @@ public class GitFilter implements Filter { doNotCache(response); response.setHeader("Content-Type", "application/x-" + service + "-result"); - final Map environments = new HashMap<>(); + Map environments = new HashMap<>(); String serverUrl; if (serverConfig.getHttpPort() != 0) serverUrl = "http://localhost:" + serverConfig.getHttpPort(); else - serverUrl = "https://localhost:" + serverConfig.getSslConfig().getPort(); + serverUrl = "https://localhost:" + serverConfig.getHttpsPort(); environments.put("ONEDEV_CURL", configManager.getSystemSetting().getCurlConfig().getExecutable()); environments.put("ONEDEV_URL", serverUrl); diff --git a/server-core/src/main/java/io/onedev/server/maintenance/DefaultDataManager.java b/server-core/src/main/java/io/onedev/server/maintenance/DefaultDataManager.java index 63aa57e8fb..1ea91d0881 100644 --- a/server-core/src/main/java/io/onedev/server/maintenance/DefaultDataManager.java +++ b/server-core/src/main/java/io/onedev/server/maintenance/DefaultDataManager.java @@ -38,7 +38,7 @@ import io.onedev.server.event.system.SystemStarting; import io.onedev.server.model.Setting; import io.onedev.server.model.Setting.Key; import io.onedev.server.model.User; -import io.onedev.server.model.support.DiscoveredJobExecutor; +import io.onedev.server.model.support.AutoDiscoveredJobExecutor; import io.onedev.server.model.support.setting.BackupSetting; import io.onedev.server.model.support.setting.GlobalIssueSetting; import io.onedev.server.model.support.setting.MailSetting; @@ -154,7 +154,7 @@ public class DefaultDataManager implements DataManager, Serializable { } setting = settingManager.getSetting(Key.JOB_EXECUTORS); if (setting == null) { - settingManager.saveJobExecutors(Lists.newArrayList(new DiscoveredJobExecutor())); + settingManager.saveJobExecutors(Lists.newArrayList(new AutoDiscoveredJobExecutor())); } setting = settingManager.getSetting(Key.MAIL); diff --git a/server-core/src/main/java/io/onedev/server/maintenance/Upgrade.java b/server-core/src/main/java/io/onedev/server/maintenance/Upgrade.java index f926e22f90..152f3a721d 100644 --- a/server-core/src/main/java/io/onedev/server/maintenance/Upgrade.java +++ b/server-core/src/main/java/io/onedev/server/maintenance/Upgrade.java @@ -110,7 +110,14 @@ public class Upgrade extends DefaultPersistManager { System.exit(1); } - if (upgradeDir.list().length != 0) { + boolean isEmpty = true; + for (File file: upgradeDir.listFiles()) { + if (!file.getName().equals("lost+found")) { + isEmpty = false; + break; + } + } + if (!isEmpty) { if (!new File(upgradeDir, "boot/bootstrap.keys").exists()) { logger.error("Invalid OneDev installation directory: {}, make sure you are specifying the top level " + "installation directory (it contains sub directories such as \"bin\", \"boot\", \"conf\", etc)", diff --git a/server-core/src/main/java/io/onedev/server/model/support/DiscoveredJobExecutor.java b/server-core/src/main/java/io/onedev/server/model/support/AutoDiscoveredJobExecutor.java similarity index 96% rename from server-core/src/main/java/io/onedev/server/model/support/DiscoveredJobExecutor.java rename to server-core/src/main/java/io/onedev/server/model/support/AutoDiscoveredJobExecutor.java index b6214646b0..3aa36c3792 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/DiscoveredJobExecutor.java +++ b/server-core/src/main/java/io/onedev/server/model/support/AutoDiscoveredJobExecutor.java @@ -13,7 +13,7 @@ import io.onedev.server.web.editable.EditableUtils; import io.onedev.server.web.editable.annotation.Editable; @Editable(order=10000, description="Discover appropriate job executor automatically to run CI jobs") -public class DiscoveredJobExecutor extends JobExecutor { +public class AutoDiscoveredJobExecutor extends JobExecutor { private static final long serialVersionUID = 1L; diff --git a/server-core/src/main/java/io/onedev/server/util/serverconfig/ServerConfig.java b/server-core/src/main/java/io/onedev/server/util/ServerConfig.java similarity index 58% rename from server-core/src/main/java/io/onedev/server/util/serverconfig/ServerConfig.java rename to server-core/src/main/java/io/onedev/server/util/ServerConfig.java index 1bf17784b8..8026bf5a42 100644 --- a/server-core/src/main/java/io/onedev/server/util/serverconfig/ServerConfig.java +++ b/server-core/src/main/java/io/onedev/server/util/ServerConfig.java @@ -1,4 +1,8 @@ -package io.onedev.server.util.serverconfig; +package io.onedev.server.util; + +import java.io.File; + +import javax.annotation.Nullable; public interface ServerConfig { @@ -12,15 +16,15 @@ public interface ServerConfig { */ int getHttpPort(); - /** - * Get ssl config of the server. - *

- * @return - * ssl config of the server, or null if ssl setting is not defined. - * In case ssl setting is not defined, {@link #getHttpPort()} must not - * return 0 - */ - SslConfig getSslConfig(); + int getHttpsPort(); + + @Nullable + File getKeystoreFile(); + + String getKeystorePassword(); + + @Nullable + File getTrustCertsDir(); /** * Get web session timeout in seconds. diff --git a/server-core/src/main/java/io/onedev/server/util/serverconfig/SslConfig.java b/server-core/src/main/java/io/onedev/server/util/serverconfig/SslConfig.java deleted file mode 100644 index e73270c45b..0000000000 --- a/server-core/src/main/java/io/onedev/server/util/serverconfig/SslConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.onedev.server.util.serverconfig; - -public interface SslConfig { - int getPort(); - - String getKeystore(); - - String getKeystorePassword(); -} diff --git a/server-core/src/main/java/io/onedev/server/web/websocket/WebSocketPolicyProvider.java b/server-core/src/main/java/io/onedev/server/web/websocket/WebSocketPolicyProvider.java index 190d4f8e6e..78627eb8b0 100644 --- a/server-core/src/main/java/io/onedev/server/web/websocket/WebSocketPolicyProvider.java +++ b/server-core/src/main/java/io/onedev/server/web/websocket/WebSocketPolicyProvider.java @@ -6,7 +6,7 @@ import javax.inject.Singleton; import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import io.onedev.server.util.serverconfig.ServerConfig; +import io.onedev.server.util.ServerConfig; @Singleton public class WebSocketPolicyProvider implements Provider { diff --git a/server-plugin/server-plugin-kubernetes/pom.xml b/server-plugin/server-plugin-kubernetes/pom.xml index 2019c8ce4b..4d2fbb08e5 100644 --- a/server-plugin/server-plugin-kubernetes/pom.xml +++ b/server-plugin/server-plugin-kubernetes/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 server-plugin-kubernetes @@ -7,6 +8,13 @@ server-plugin 3.0.1 + + + org.bouncycastle + bcprov-jdk15on + 1.62 + + io.onedev.server.plugin.kubernetes.KubernetesModule diff --git a/server-plugin/server-plugin-kubernetes/src/main/java/io/onedev/server/plugin/kubernetes/KubernetesExecutor.java b/server-plugin/server-plugin-kubernetes/src/main/java/io/onedev/server/plugin/kubernetes/KubernetesExecutor.java index 49bd371f7d..207f730fbc 100644 --- a/server-plugin/server-plugin-kubernetes/src/main/java/io/onedev/server/plugin/kubernetes/KubernetesExecutor.java +++ b/server-plugin/server-plugin-kubernetes/src/main/java/io/onedev/server/plugin/kubernetes/KubernetesExecutor.java @@ -1,10 +1,21 @@ package io.onedev.server.plugin.kubernetes; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.Serializable; +import java.io.StringWriter; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -16,6 +27,8 @@ import javax.annotation.Nullable; import org.apache.commons.codec.Charsets; import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; import org.hibernate.validator.constraints.NotEmpty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +58,7 @@ import io.onedev.server.model.support.JobExecutor; import io.onedev.server.model.support.RegistryLogin; import io.onedev.server.plugin.kubernetes.KubernetesExecutor.TestData; import io.onedev.server.util.JobLogger; +import io.onedev.server.util.ServerConfig; import io.onedev.server.util.inputspec.SecretInput; import io.onedev.server.web.editable.annotation.Editable; import io.onedev.server.web.editable.annotation.NameOfEmptyValue; @@ -410,6 +424,72 @@ public class KubernetesExecutor extends JobExecutor implements Testable configMapData = new LinkedHashMap<>(); + ServerConfig serverConfig = OneDev.getInstance(ServerConfig.class); + File keystoreFile = serverConfig.getKeystoreFile(); + if (keystoreFile != null) { + try (InputStream is = new FileInputStream(keystoreFile)) { + KeyStore keystore = KeyStore.getInstance("pkcs12"); + keystore.load(is, serverConfig.getKeystorePassword().toCharArray()); + Enumeration aliases = keystore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + String siteCertContent = getCertContent(keystore.getCertificate(alias)); + String safeAlias = alias.replaceAll("[^a-zA-Z0-9\\.\\_]", "-"); + configMapData.put("keystore-site-cert-" + safeAlias + ".pem", siteCertContent); + + Certificate chain[] = keystore.getCertificateChain(alias); + if (chain != null) { + for (int i=0; i configMapDef = Maps.newLinkedHashMap( + "apiVersion", "v1", + "kind", "ConfigMap", + "metadata", Maps.newLinkedHashMap( + "generateName", "configmap-", + "namespace", "onedev"), + "data", configMapData); + return createResource(configMapDef, new HashSet<>(), logger); + } else { + return null; + } + } + private void execute(String dockerImage, String jobToken, JobLogger logger, @Nullable JobContext jobContext) { logger.log("Executing job with Kubernetes executor..."); @@ -417,10 +497,12 @@ public class KubernetesExecutor extends JobExecutor implements Testable jobSecrets = Maps.newLinkedHashMap(KubernetesHelper.ENV_JOB_TOKEN, jobToken); jobSecretName = createSecret(jobSecrets, null, logger); imagePullSecretName = createImagePullSecret(logger); + trustCertsConfigMapName = createTrustCertsConfigMap(logger); String osName = getOSName(logger); @@ -433,28 +515,36 @@ public class KubernetesExecutor extends JobExecutor implements Testable ciPathMount = Maps.newLinkedHashMap( + Map ciHomeMount = Maps.newLinkedHashMap( "name", "ci-home", "mountPath", containerCIHome); Map cacheHomeMount = Maps.newLinkedHashMap( "name", "cache-home", "mountPath", containerCacheHome); + Map trustCertsMount = Maps.newLinkedHashMap( + "name", "trust-certs-home", + "mountPath", trustCertsHome); - List volumeMounts = Lists.newArrayList(ciPathMount, cacheHomeMount); + List volumeMounts = Lists.newArrayList(ciHomeMount, cacheHomeMount); + if (trustCertsConfigMapName != null) + volumeMounts.add(trustCertsMount); mainContainerSpec.put("volumeMounts", volumeMounts); @@ -512,8 +602,15 @@ public class KubernetesExecutor extends JobExecutor implements TestablenewArrayList(ciHomeVolume, cacheHomeVolume)); + List volumes = Lists.newArrayList(ciHomeVolume, cacheHomeVolume); + if (trustCertsConfigMapName != null) { + Map trustCertsHomeVolume = Maps.newLinkedHashMap( + "name", "trust-certs-home", + "configMap", Maps.newLinkedHashMap( + "name", trustCertsConfigMapName)); + volumes.add(trustCertsHomeVolume); + } + podSpec.put("volumes", volumes); Map podDef = Maps.newLinkedHashMap( "apiVersion", "v1", @@ -648,6 +745,8 @@ public class KubernetesExecutor extends JobExecutor implements Testable