[skip ci] remove some extensions
This commit is contained in:
parent
8304b2d8a3
commit
7355f9f51d
16 changed files with 0 additions and 858 deletions
|
@ -1,14 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.demos
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.local
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.helloWorld() = task {
|
|
||||||
cmd("echo Hello world!")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
local().helloWorld()
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.demos
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.*
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints some information and settings of the operating system and environment.
|
|
||||||
*
|
|
||||||
* For running locally no arguments are required.
|
|
||||||
* For running remotely either 2 or 3 arguments must be provided:
|
|
||||||
* either host and user for connection by ssh key ()
|
|
||||||
* or host, user and password for password-authenticated connection.
|
|
||||||
* E.g. 172.0.0.123 username or 172.0.0.123 username password
|
|
||||||
*/
|
|
||||||
fun main(vararg args: String) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
local().printInfos()
|
|
||||||
} else {
|
|
||||||
if (args.size !in 2..3) {
|
|
||||||
println("Wrong number of arguments. Please specify either host and user if connection is done by ssh key or otherwise host, user and password. E.g. 172.0.0.123 username password")
|
|
||||||
} else {
|
|
||||||
val password = if (args.size == 2) null else Secret(args[2])
|
|
||||||
remote(args[0], args[1], password = password).printInfos()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.printInfos() = task {
|
|
||||||
println("\nUbuntu Version:\n${ubuntuVersion()}")
|
|
||||||
println("\nCurrent directory:\n${currentDir()}")
|
|
||||||
println("\nTime zone:\n${timeZone()}")
|
|
||||||
|
|
||||||
val dir = cmd("pwd").out
|
|
||||||
println("\nCurrent directory: $dir")
|
|
||||||
|
|
||||||
ProvResult(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.ubuntuVersion(): String? {
|
|
||||||
return cmd("lsb_release -a").out
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.currentDir(): String? {
|
|
||||||
return cmd("pwd").out
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.timeZone(): String? {
|
|
||||||
return cmd("cat /etc/timezone").out
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.certbot
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provisions a certbot for the specified serverName and email to obtain and renew letsencrypt certificates
|
|
||||||
* Parameter can be used to specify certbot options e.g. "--nginx" to configure nginx, see https://certbot.eff.org/docs/using.html#certbot-command-line-options
|
|
||||||
*/
|
|
||||||
fun Prov.provisionCertbot(serverName: String, email: String?, additionalOptions: String? = "") = task {
|
|
||||||
aptInstall("snapd")
|
|
||||||
sh("""
|
|
||||||
sudo snap install core; sudo snap refresh core
|
|
||||||
sudo snap install --classic certbot
|
|
||||||
""".trimIndent())
|
|
||||||
|
|
||||||
if (!checkFile("/usr/bin/certbot")) {
|
|
||||||
cmd("sudo ln -s /snap/bin/certbot /usr/bin/certbot")
|
|
||||||
val emailOption = email?.let { " -m $it" } ?: "--register-unsafely-without-email"
|
|
||||||
cmd("sudo certbot $additionalOptions -n --agree-tos $emailOption -d $serverName")
|
|
||||||
} else {
|
|
||||||
ProvResult(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nexus
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.docker.containerRuns
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.remote
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.createUser
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.certbot.provisionCertbot
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base.NginxConf
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base.nginxReverseProxyHttpConfig
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.provisionNginxStandAlone
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provisions sonatype nexus in a docker container.
|
|
||||||
* If you would want nexus to be accessible directly from the internet (e.g. for test or demo reasons)
|
|
||||||
* set parameter portAccessibleFromNetwork to true.
|
|
||||||
*/
|
|
||||||
fun Prov.provisionNexusWithDocker(portAccessibleFromNetwork: Boolean = false) = task {
|
|
||||||
// https://blog.sonatype.com/sonatype-nexus-installation-using-docker
|
|
||||||
// https://medium.com/@AhGh/how-to-setup-sonatype-nexus-3-repository-manager-using-docker-7ff89bc311ce
|
|
||||||
aptInstall("docker.io")
|
|
||||||
|
|
||||||
if (!containerRuns("nexus")) {
|
|
||||||
val volume = "nexus-data"
|
|
||||||
if (!cmdNoEval("docker volume inspect $volume").success) {
|
|
||||||
cmd("docker volume create --name $volume")
|
|
||||||
}
|
|
||||||
cmd("sudo docker run -d --restart unless-stopped -p 8081:8081 --name nexus -v nexus-data:/nexus-data sonatype/nexus3")
|
|
||||||
|
|
||||||
for (n in 0..3) {
|
|
||||||
if (checkFile("/var/lib/docker/volumes/$volume/_data/admin.password", sudo = true)) {
|
|
||||||
val res = cmd("sudo cat /var/lib/docker/volumes/$volume/_data/admin.password")
|
|
||||||
println("Admin Password:" + res.out)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
Thread.sleep(20000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!portAccessibleFromNetwork) {
|
|
||||||
val netIf = getDefaultNetworkingInterface()
|
|
||||||
netIf?.also {
|
|
||||||
val iptablesParameters = "DOCKER-USER -i $it ! -s 127.0.0.1 -j DROP"
|
|
||||||
if (!cmdNoEval("sudo iptables -C $iptablesParameters").success) {
|
|
||||||
cmd("sudo iptables -I $iptablesParameters")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ProvResult(true) // dummy
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Prov.getDefaultNetworkingInterface(): String? {
|
|
||||||
return cmd("route | grep \"^default\" | grep -o \"[^ ]*\$\"\n").out?.trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provisions sonatype nexus on the specified host.
|
|
||||||
* Creates user "nexus" on the remote system.
|
|
||||||
* Installs nexus in a docker container behind an nginx reverse proxy with ssl using letsencrypt certificates.
|
|
||||||
*
|
|
||||||
* To run this method it is required to have ssl root access to the host.
|
|
||||||
*/
|
|
||||||
@Suppress("unused") // to be used externally
|
|
||||||
fun provisionNexusServer(serverName: String, certbotEmail: String) {
|
|
||||||
val userName = "nexus" + 7
|
|
||||||
remote(serverName, "root").task {
|
|
||||||
createUser(userName, copyAuthorizedSshKeysFromCurrentUser = true, sudo = true)
|
|
||||||
}
|
|
||||||
remote(serverName, userName).task {
|
|
||||||
provisionNexusWithDocker()
|
|
||||||
|
|
||||||
if (provisionNginxStandAlone(NginxConf.nginxReverseProxyHttpConfig(serverName)).success) {
|
|
||||||
|
|
||||||
cmd("sudo cat /etc/nginx/nginx.conf")
|
|
||||||
|
|
||||||
provisionCertbot(serverName, certbotEmail, "--nginx")
|
|
||||||
|
|
||||||
optional {
|
|
||||||
cmd("sudo cat /etc/nginx/nginx.conf")
|
|
||||||
cmd("sudo sed -i 's/X-Forwarded-Proto \"http\"/X-Forwarded-Proto \"https\"/g' /etc/nginx/nginx.conf")
|
|
||||||
cmd("sudo systemctl reload nginx")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ProvResult(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nexus.base
|
|
||||||
|
|
||||||
fun reverseProxyConfigHttpPort80(serverName: String): String {
|
|
||||||
// see https://help.sonatype.com/repomanager3/installation/run-behind-a-reverse-proxy
|
|
||||||
return """
|
|
||||||
events {} # event context have to be defined to consider config valid
|
|
||||||
|
|
||||||
http {
|
|
||||||
|
|
||||||
proxy_send_timeout 120;
|
|
||||||
proxy_read_timeout 300;
|
|
||||||
proxy_buffering off;
|
|
||||||
keepalive_timeout 5 5;
|
|
||||||
tcp_nodelay on;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name $serverName;
|
|
||||||
|
|
||||||
# allow large uploads of files
|
|
||||||
client_max_body_size 1G;
|
|
||||||
|
|
||||||
# optimize downloading files larger than 1G
|
|
||||||
#proxy_max_temp_file_size 2G;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
|
|
||||||
proxy_pass http://127.0.0.1:8081/;
|
|
||||||
proxy_set_header Host ${'$'}host;
|
|
||||||
proxy_set_header X-Real-IP ${'$'}remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For ${'$'}proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto "http";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun reverseProxyConfigSsl(serverName: String, ssl_certificate: String? = null, ssl_certificate_key: String? = null): String {
|
|
||||||
// see https://help.sonatype.com/repomanager3/installation/run-behind-a-reverse-proxy
|
|
||||||
|
|
||||||
val sslCertificateEntry = ssl_certificate?.let { "ssl_certificate $ssl_certificate;" } ?: "ssl_certificate /etc/letsencrypt/live/$serverName/fullchain.pem;"
|
|
||||||
val sslCertificateKeyEntry = ssl_certificate?.let { "ssl_certificate_key $ssl_certificate_key;" } ?: "ssl_certificate_key /etc/letsencrypt/live/$serverName/privkey.pem"
|
|
||||||
|
|
||||||
return """
|
|
||||||
events {} # event context have to be defined to consider config valid
|
|
||||||
|
|
||||||
http {
|
|
||||||
|
|
||||||
proxy_send_timeout 120;
|
|
||||||
proxy_read_timeout 300;
|
|
||||||
proxy_buffering off;
|
|
||||||
keepalive_timeout 5 5;
|
|
||||||
tcp_nodelay on;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen *:443 ssl;
|
|
||||||
server_name $serverName;
|
|
||||||
|
|
||||||
# allow large uploads of files
|
|
||||||
client_max_body_size 1G;
|
|
||||||
|
|
||||||
# optimize downloading files larger than 1G
|
|
||||||
# proxy_max_temp_file_size 2G;
|
|
||||||
|
|
||||||
$sslCertificateEntry
|
|
||||||
$sslCertificateKeyEntry
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
|
|
||||||
proxy_pass http://127.0.0.1:8081/;
|
|
||||||
proxy_set_header Host ${'$'}host;
|
|
||||||
proxy_set_header X-Real-IP ${'$'}remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For ${'$'}proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto "https";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base.NginxConf
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base.createNginxLocationFolders
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
|
||||||
|
|
||||||
|
|
||||||
internal const val NGINX_CONFIG_FILE = "/etc/nginx/nginx.conf"
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.provisionNginxStandAlone(config: NginxConf? = null) = task {
|
|
||||||
|
|
||||||
aptInstall("nginx")
|
|
||||||
|
|
||||||
createNginxLocationFolders()
|
|
||||||
|
|
||||||
if (config != null) {
|
|
||||||
if (checkFile(NGINX_CONFIG_FILE)) {
|
|
||||||
cmd("sudo mv $NGINX_CONFIG_FILE $NGINX_CONFIG_FILE-orig")
|
|
||||||
}
|
|
||||||
createFile(NGINX_CONFIG_FILE, config.conf, sudo = true)
|
|
||||||
val configCheck = cmd("sudo nginx -t")
|
|
||||||
if (configCheck.success) {
|
|
||||||
cmd("sudo service nginx restart")
|
|
||||||
} else {
|
|
||||||
ProvResult(false, err = "Nginx config is incorrect:\n" + configCheck.err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ProvResult(true) // dummy
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base
|
|
||||||
|
|
||||||
class NginxConf(val conf: String = NGINX_MINIMAL_CONF) {
|
|
||||||
companion object {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const val NGINX_MINIMAL_CONF = """
|
|
||||||
events {}
|
|
||||||
|
|
||||||
http {
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
return 200 'Hi from nginx!';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("unused") // use later
|
|
||||||
fun NginxConf.Companion.nginxHttpConf(
|
|
||||||
serverName: String = "localhost"
|
|
||||||
): NginxConf {
|
|
||||||
return NginxConf(
|
|
||||||
"""
|
|
||||||
events {}
|
|
||||||
|
|
||||||
http {
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name $serverName;
|
|
||||||
|
|
||||||
include /etc/nginx/locations-enabled/port80*$locationsFileExtension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun NginxConf.Companion.nginxHttpsConfWithLocationFiles(
|
|
||||||
sslCertificate: String = "/etc/nginx/ssl/cert/selfsigned.crt",
|
|
||||||
sslCertificateKey: String = "/etc/nginx/ssl/private/selfsigned.key"
|
|
||||||
): NginxConf {
|
|
||||||
return NginxConf(
|
|
||||||
"""
|
|
||||||
events {}
|
|
||||||
|
|
||||||
http {
|
|
||||||
server {
|
|
||||||
listen 443 ssl;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
ssl_certificate $sslCertificate;
|
|
||||||
ssl_certificate_key $sslCertificateKey;
|
|
||||||
|
|
||||||
include /etc/nginx/locations-enabled/port443*$locationsFileExtension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("unused") // use later
|
|
||||||
fun NginxConf.Companion.nginxReverseProxySslConfig(
|
|
||||||
serverName: String,
|
|
||||||
ssl_certificate: String? = null,
|
|
||||||
ssl_certificate_key: String? = null
|
|
||||||
): NginxConf {
|
|
||||||
// see https://help.sonatype.com/repomanager3/installation/run-behind-a-reverse-proxy
|
|
||||||
|
|
||||||
val sslCertificateEntry = ssl_certificate?.let { "ssl_certificate $ssl_certificate;" }
|
|
||||||
?: "ssl_certificate /etc/letsencrypt/live/$serverName/fullchain.pem;"
|
|
||||||
val sslCertificateKeyEntry = ssl_certificate?.let { "ssl_certificate_key $ssl_certificate_key;" }
|
|
||||||
?: "ssl_certificate_key /etc/letsencrypt/live/$serverName/privkey.pem"
|
|
||||||
|
|
||||||
return NginxConf(
|
|
||||||
"""
|
|
||||||
events {} # event context have to be defined to consider config valid
|
|
||||||
|
|
||||||
http {
|
|
||||||
|
|
||||||
proxy_send_timeout 120;
|
|
||||||
proxy_read_timeout 300;
|
|
||||||
proxy_buffering off;
|
|
||||||
keepalive_timeout 5 5;
|
|
||||||
tcp_nodelay on;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen *:443 ssl;
|
|
||||||
server_name $serverName;
|
|
||||||
|
|
||||||
# allow large uploads of files
|
|
||||||
client_max_body_size 1G;
|
|
||||||
|
|
||||||
# optimize downloading files larger than 1G
|
|
||||||
#proxy_max_temp_file_size 2G;
|
|
||||||
|
|
||||||
$sslCertificateEntry
|
|
||||||
$sslCertificateKeyEntry
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
|
|
||||||
proxy_pass http://127.0.0.1:8081/;
|
|
||||||
proxy_set_header Host ${'$'}host;
|
|
||||||
proxy_set_header X-Real-IP ${'$'}remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For ${'$'}proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto "https";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("unused") // use later
|
|
||||||
fun NginxConf.Companion.nginxReverseProxyHttpConfig(
|
|
||||||
serverName: String
|
|
||||||
): NginxConf {
|
|
||||||
// see https://help.sonatype.com/repomanager3/installation/run-behind-a-reverse-proxy
|
|
||||||
|
|
||||||
return NginxConf(
|
|
||||||
"""
|
|
||||||
events {} # event context have to be defined to consider config valid
|
|
||||||
|
|
||||||
http {
|
|
||||||
|
|
||||||
proxy_send_timeout 120;
|
|
||||||
proxy_read_timeout 300;
|
|
||||||
proxy_buffering off;
|
|
||||||
keepalive_timeout 5 5;
|
|
||||||
tcp_nodelay on;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen *:80;
|
|
||||||
server_name $serverName;
|
|
||||||
|
|
||||||
# allow large uploads of files
|
|
||||||
client_max_body_size 1G;
|
|
||||||
|
|
||||||
# optimize downloading files larger than 1G
|
|
||||||
#proxy_max_temp_file_size 2G;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
|
|
||||||
proxy_pass http://127.0.0.1:8081/;
|
|
||||||
proxy_set_header Host ${'$'}host;
|
|
||||||
proxy_set_header X-Real-IP ${'$'}remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For ${'$'}proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto "https";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDirs
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.replaceTextInFile
|
|
||||||
|
|
||||||
|
|
||||||
internal const val locationsAvailableDir = "/etc/nginx/locations-available/"
|
|
||||||
internal const val locationsEnabledDir = "/etc/nginx/locations-enabled/"
|
|
||||||
internal const val locationsFileExtension = ".locations"
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.createNginxLocationFolders() = task {
|
|
||||||
createDirs(locationsEnabledDir, sudo = true)
|
|
||||||
createDirs(locationsAvailableDir, sudo = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.nginxIncludeLocationFolders() = task {
|
|
||||||
replaceTextInFile("/etc/nginx/nginx.conf", "listen 80;\n",
|
|
||||||
"""listen 80;
|
|
||||||
include ${locationsAvailableDir}port80*$locationsFileExtension;
|
|
||||||
include ${locationsEnabledDir}port443*$locationsFileExtension;
|
|
||||||
""")
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDirs
|
|
||||||
|
|
||||||
|
|
||||||
internal val certificateName = "selfsigned"
|
|
||||||
internal val sslDays = 365
|
|
||||||
val dirSslCert="/etc/nginx/ssl/cert"
|
|
||||||
val dirSslKey="/etc/nginx/ssl/private"
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.nginxCreateSelfSignedCertificate(
|
|
||||||
country: String = "DE",
|
|
||||||
state: String = "test",
|
|
||||||
locality: String = "test",
|
|
||||||
organization: String = "test",
|
|
||||||
organizationalUnit: String = "test",
|
|
||||||
commonName: String = "test",
|
|
||||||
email : String = "test@test.net"
|
|
||||||
) = task {
|
|
||||||
// inspired by https://gist.github.com/adrianorsouza/2bbfe5e197ce1c0b97c8
|
|
||||||
createDirs(dirSslCert, sudo = true)
|
|
||||||
createDirs(dirSslKey, sudo = true)
|
|
||||||
cmd("cd $dirSslKey && sudo openssl req -x509 -nodes -newkey rsa:2048 -keyout $certificateName.key -out $certificateName.crt -days $sslDays -subj \"/C=$country/ST=$state/L=$locality/O=$organization/OU=$organizationalUnit/CN=$commonName/emailAddress=$email\"")
|
|
||||||
cmd("sudo mv $dirSslKey/$certificateName.crt $dirSslCert/")
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.prometheus
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.prometheus.base.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provisions prometheus monitoring.
|
|
||||||
* If running behind an nginx, pls specify the hostname in parameter nginxHost (e.g. mydomain.com).
|
|
||||||
* To run it without nodeExporter (which provides system data to prometheus), set withNodeExporter to false.
|
|
||||||
*/
|
|
||||||
@Suppress("unused")
|
|
||||||
fun Prov.provisionPrometheusDocker(nginxHost: String? = null, withNodeExporter: Boolean = true) = task {
|
|
||||||
configurePrometheusDocker()
|
|
||||||
if (withNodeExporter) {
|
|
||||||
installNodeExporter()
|
|
||||||
runNodeExporter()
|
|
||||||
addNodeExporterToPrometheusConf()
|
|
||||||
}
|
|
||||||
runPrometheusDocker(nginxHost)
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.prometheus.base
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDir
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContainsText
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.replaceTextInFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.whoami
|
|
||||||
|
|
||||||
|
|
||||||
internal val defaultInstallationDir = "/usr/local/bin/"
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.installNodeExporter() = task {
|
|
||||||
// inspired by https://devopscube.com/monitor-linux-servers-prometheus-node-exporter/ and
|
|
||||||
// https://www.howtoforge.com/tutorial/how-to-install-prometheus-and-node-exporter-on-centos-8/#step-install-and-configure-nodeexporter
|
|
||||||
val downloadFileBasename = "node_exporter-1.0.1.linux-amd64"
|
|
||||||
val downloadFile = "$downloadFileBasename.tar.gz"
|
|
||||||
val downloadPath = "~/tmp/"
|
|
||||||
val fqFile = downloadPath + downloadFile
|
|
||||||
|
|
||||||
aptInstall("curl")
|
|
||||||
createDir("tmp")
|
|
||||||
sh(
|
|
||||||
"""
|
|
||||||
cd tmp && curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.0.1/$downloadFile --output $downloadFile
|
|
||||||
cd tmp && tar -xvf $fqFile -C $downloadPath
|
|
||||||
|
|
||||||
sudo mv $downloadPath$downloadFileBasename/node_exporter $defaultInstallationDir"""
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.runNodeExporter() = task {
|
|
||||||
createFile("/etc/systemd/system/node_exporter.service", nodeExporterServiceConf(whoami()?:"nouserfound"), sudo = true)
|
|
||||||
|
|
||||||
sh("""
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
|
|
||||||
# start the node_exporter service and enable it to launch everytime at system startup.
|
|
||||||
sudo systemctl start node_exporter
|
|
||||||
sudo systemctl enable node_exporter
|
|
||||||
|
|
||||||
# check if running
|
|
||||||
sudo systemctl status node_exporter --no-pager -l
|
|
||||||
""")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.addNodeExporterToPrometheusConf (
|
|
||||||
prometheusConf: String = "/etc/prometheus/prometheus.yml",
|
|
||||||
sudo: Boolean = true
|
|
||||||
) = task {
|
|
||||||
val prometheusConfNodeExporter = """
|
|
||||||
scrape_configs:
|
|
||||||
- job_name: 'node_exporter'
|
|
||||||
static_configs:
|
|
||||||
- targets: ['172.17.0.1:9100']
|
|
||||||
"""
|
|
||||||
if (!fileContainsText(prometheusConf, "- job_name: 'node_exporter'", sudo)) {
|
|
||||||
replaceTextInFile(prometheusConf, "\nscrape_configs:\n", prometheusConfNodeExporter)
|
|
||||||
}
|
|
||||||
// cmd("sudo systemctl restart prometheus") for standalone
|
|
||||||
cmd("sudo docker restart prometheus")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun nodeExporterServiceConf(user: String, installationDir: String = defaultInstallationDir): String {
|
|
||||||
return """
|
|
||||||
[Unit]
|
|
||||||
Description=Node Exporter
|
|
||||||
Wants=network-online.target
|
|
||||||
After=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=$user
|
|
||||||
ExecStart=${installationDir}node_exporter
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=default.target
|
|
||||||
"""
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.prometheus.base
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.docker.containerRuns
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDirs
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
|
||||||
|
|
||||||
|
|
||||||
internal val configDir = "/etc/prometheus/"
|
|
||||||
internal val configFile = "prometheus.yml"
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.configurePrometheusDocker(config: String = prometheusDefaultConfig()) = task {
|
|
||||||
createDirs(configDir, sudo = true)
|
|
||||||
createFile(configDir + configFile, config, sudo = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.runPrometheusDocker(nginxHost: String? = null) = task {
|
|
||||||
aptInstall("docker.io")
|
|
||||||
|
|
||||||
val containerName = "prometheus"
|
|
||||||
|
|
||||||
if (containerRuns(containerName)) {
|
|
||||||
cmd("sudo docker restart $containerName")
|
|
||||||
} else {
|
|
||||||
if (nginxHost == null) {
|
|
||||||
cmd(
|
|
||||||
"sudo docker run -d -p 9090:9090 " +
|
|
||||||
" --name $containerName " +
|
|
||||||
" --restart on-failure:1" +
|
|
||||||
" -v prometheus-data:/prometheus" +
|
|
||||||
" -v $configDir$configFile:/etc/prometheus/prometheus.yml " +
|
|
||||||
" prom/prometheus"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
cmd(
|
|
||||||
"sudo docker run -d -p 9090:9090 " +
|
|
||||||
" --name $containerName " +
|
|
||||||
" --restart on-failure:1" +
|
|
||||||
" -v prometheus-data:/prometheus" +
|
|
||||||
" -v $configDir$configFile:/etc/prometheus/prometheus.yml " +
|
|
||||||
" prom/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/prometheus " +
|
|
||||||
"--web.console.libraries=/usr/share/prometheus/console_libraries " +
|
|
||||||
"--web.console.templates=/usr/share/prometheus/consoles " +
|
|
||||||
"--web.external-url=http://$nginxHost/prometheus"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun prometheusDefaultConfig() =
|
|
||||||
"""
|
|
||||||
global:
|
|
||||||
scrape_interval: 15s # By default, scrape targets every 15 seconds.
|
|
||||||
|
|
||||||
# A scrape configuration containing exactly one endpoint to scrape:
|
|
||||||
# Here it's Prometheus itself.
|
|
||||||
scrape_configs:
|
|
||||||
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
|
|
||||||
- job_name: 'prometheus'
|
|
||||||
static_configs:
|
|
||||||
- targets: ['localhost:9090']
|
|
||||||
|
|
||||||
remote_write:
|
|
||||||
- url: "<Your Metrics instance remote_write endpoint>"
|
|
||||||
basic_auth:
|
|
||||||
username: "your grafana username"
|
|
||||||
password: "your Grafana API key"
|
|
||||||
"""
|
|
|
@ -1,5 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.prometheus.base
|
|
||||||
|
|
||||||
val prometheusNginxConfig = """
|
|
||||||
proxy_pass http://localhost:9090/prometheus;
|
|
||||||
"""
|
|
|
@ -1,25 +0,0 @@
|
||||||
package nexus
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nexus.provisionNexusWithDocker
|
|
||||||
import org.junit.jupiter.api.Assertions.assertTrue
|
|
||||||
import org.junit.jupiter.api.Disabled
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
|
|
||||||
internal class ProvisionNexusKtTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled("Find out how to run docker in docker")
|
|
||||||
fun provisionNexusWithDocker() {
|
|
||||||
// given
|
|
||||||
val a = defaultTestContainer()
|
|
||||||
|
|
||||||
// when
|
|
||||||
val res = a.task {
|
|
||||||
provisionNexusWithDocker()
|
|
||||||
}
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(res.success)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base.*
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.replaceTextInFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
|
||||||
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
|
|
||||||
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
|
||||||
import org.junit.jupiter.api.Assertions.assertTrue
|
|
||||||
import org.junit.jupiter.api.Disabled
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
|
|
||||||
|
|
||||||
internal class ProvisionNginxKtTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@ContainerTest
|
|
||||||
@Disabled // Not running on (unprivileged ??) container
|
|
||||||
fun provisionNginxStandAlone_customConfig() {
|
|
||||||
// given
|
|
||||||
val a = defaultTestContainer()
|
|
||||||
val config = """
|
|
||||||
events {} # event context have to be defined to consider config valid
|
|
||||||
|
|
||||||
http {
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
return 200 "Hello";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
a.aptInstall("curl")
|
|
||||||
|
|
||||||
// when
|
|
||||||
val res = a.task {
|
|
||||||
provisionNginxStandAlone(NginxConf(config))
|
|
||||||
cmd("curl localhost")
|
|
||||||
}
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(res.success)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@ContainerTest
|
|
||||||
@Disabled // Not running on (unprivileged ??) container
|
|
||||||
fun provisionNginxStandAlone_defaultConfig() {
|
|
||||||
// given
|
|
||||||
val a = defaultTestContainer()
|
|
||||||
|
|
||||||
// when
|
|
||||||
val res = a.task {
|
|
||||||
provisionNginxStandAlone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(res.success)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@ContainerTest
|
|
||||||
@Disabled // Not running on (unprivileged ??) container
|
|
||||||
fun provisionNginxStandAlone_sslConfig() {
|
|
||||||
// given
|
|
||||||
val a = defaultTestContainer()
|
|
||||||
a.task {
|
|
||||||
val file = "/etc/ssl/openssl.cnf"
|
|
||||||
if (checkFile(file)) {
|
|
||||||
replaceTextInFile(file, "RANDFILE", "#RANDFILE")
|
|
||||||
}
|
|
||||||
aptInstall("openssl")
|
|
||||||
}
|
|
||||||
|
|
||||||
// when
|
|
||||||
val res = a.task {
|
|
||||||
nginxCreateSelfSignedCertificate()
|
|
||||||
|
|
||||||
provisionNginxStandAlone(
|
|
||||||
NginxConf.nginxReverseProxySslConfig(
|
|
||||||
"localhost",
|
|
||||||
dirSslCert + "/" + certificateName + ".crt",
|
|
||||||
dirSslKey + "/" + certificateName + ".key"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(res.success)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.base
|
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContainsText
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.NGINX_CONFIG_FILE
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.extensions.server_software.standalone_server.nginx.provisionNginxStandAlone
|
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
|
||||||
import org.junit.jupiter.api.Assertions.assertTrue
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
|
|
||||||
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
|
||||||
import org.domaindrivenarchitecture.provs.test.tags.NonCi
|
|
||||||
import org.junit.jupiter.api.Disabled
|
|
||||||
|
|
||||||
internal class LocationsKtTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@ContainerTest
|
|
||||||
@NonCi
|
|
||||||
@Disabled // todo: fix test
|
|
||||||
fun nginxIncludeLocationFolders() {
|
|
||||||
// given
|
|
||||||
val a = defaultTestContainer()
|
|
||||||
a.provisionNginxStandAlone()
|
|
||||||
a.createFile(NGINX_CONFIG_FILE, NGINX_MINIMAL_CONF, sudo = true)
|
|
||||||
|
|
||||||
// when
|
|
||||||
val res = a.nginxIncludeLocationFolders()
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(res.success)
|
|
||||||
assertTrue(a.fileContainsText(
|
|
||||||
NGINX_CONFIG_FILE, """listen 80;
|
|
||||||
include /etc/nginx/locations-enabled/port80*.conf
|
|
||||||
include /etc/nginx/locations-enabled/port443*.conf"""))
|
|
||||||
// just 1 occurrence
|
|
||||||
assertEquals("1", a.cmd("grep -o 'listen 80;' $NGINX_CONFIG_FILE | wc -l").out?.trim())
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue