Merge pull request #5682 from dokku/build-digitalocean-image

Build Digitalocean image automatically upon release
This commit is contained in:
josegonzalez
2023-02-16 19:37:32 -05:00
committed by GitHub
19 changed files with 1316 additions and 32 deletions

View File

@@ -34,6 +34,23 @@ jobs:
config: '.github/linters/.markdown-lint.yml'
args: './README.md'
packer:
name: packer
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup packer
uses: hashicorp/setup-packer@main
with:
version: latest
- name: Run packer init
run: "make image/init/digitalocean"
- name: Run `packer validate`
env:
DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
run: "make image/validate/digitalocean"
shellcheck:
name: shellcheck
runs-on: ubuntu-20.04

View File

@@ -72,6 +72,40 @@ jobs:
name: build
path: build
build-digitalocean:
name: build-digitalocean
runs-on: ubuntu-20.04
needs: release
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup packer
uses: hashicorp/setup-packer@main
with:
version: latest
- name: Run packer init
run: "make image/init/digitalocean"
- name: Run `packer validate`
env:
DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
PKR_VAR_dokku_version: ${{ needs.release.outputs.version }}
run: "make image/validate/digitalocean"
- name: Bump Digitalocean Image
env:
DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
PKR_VAR_dokku_version: ${{ needs.release.outputs.version }}
run: "make image/build/digitalocean"
- name: upload packages
uses: actions/upload-artifact@v3
with:
name: digitalocean-manifest.json
path: digitalocean-manifest.json
bump-azure:
name: bump-azure
runs-on: ubuntu-20.04

View File

@@ -0,0 +1,95 @@
# You may add here your
# server {
# ...
# }
# statements for each of your virtual hosts to this file
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/html;
index index.php index.html index.htm;
# Make site accessible from http://localhost/
server_name localhost;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# root html;
# index index.html index.htm;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
# HTTPS server
#
#server {
# listen 443;
# server_name localhost;
#
# root html;
# index index.html index.htm;
#
# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
#
# ssl_session_timeout 5m;
#
# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
# ssl_prefer_server_ciphers on;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}

View File

@@ -0,0 +1,21 @@
#!/bin/sh
#
# Configured as part of the DigitalOcean 1-Click Image build process
myip=$(hostname -I | awk '{print$1}')
cat <<EOF
********************************************************************************
Welcome to DigitalOcean's 1-Click Dokku Droplet.
To keep this Droplet secure, the UFW firewall is enabled.
All ports are BLOCKED except 22 (SSH), 80 (HTTP), 443 (HTTPS).
In a web browser, you can view:
* The Dokku One-Click Quickstart guide: https://do.co/dokku1804#start
For help and more information, visit https://do.co/dokku1804
********************************************************************************
To delete this message of the day: rm -rf $(readlink -f ${0})
To remove the default web landing page: rm -rf /etc/nginx/sites-available/digitalocean
EOF

View File

@@ -0,0 +1,25 @@
#!/bin/bash -x
set +e
exec > >(tee /var/log/one_click_setup.log) 2>&1
ufw --force enable
printf "dokku dokku/hostname string %s" hostname | debconf-set-selections
export DEBIAN_FRONTEND=noninteractive
export LANG=C
export LC_ALL=C
# Install Dokku....
for count in {1..30}; do
dpkg -i /var/lib/digitalocean/debs/*deb || /bin/true
apt-get -f install || /bin/true
version=$(dpkg-query --showformat='${Version}' -W dokku)
if [[ -n "$version" ]]; then
ran=0
exit 0
else
count=$((count + 1))
fi
sleep 5
done

View File

@@ -0,0 +1,9 @@
#!/bin/bash
exec > >(tee /var/log/one_click_setup.log) 2>&1
# Remove the force command
sed -e '/Match user root/d' \
-e '/.*ForceCommand.*droplet.*/d' \
-i /etc/ssh/sshd_config
systemctl restart ssh

View File

@@ -0,0 +1,169 @@
<html>
<head>
<style>
body {
font-family: ProximaNova;
font-size: 15px;
font-style: normal;
font-stretch: normal;
line-height: 1;
letter-spacing: normal;
margin: 0;
}
.button {
border-radius: 3px;
background-color: #0069ff;
color: #ffffff;
display: flex;
flex-direction: column;
height: 48px;
justify-content: center;
text-decoration: none;
width: 148px;
}
.content {
align-items: center;
border: solid 2px #f1f1f1;
border-radius: 3px;
display: flex;
flex-direction: column;
margin: 32px auto;
padding: 32px;
text-align: center;
width: 960px;
;
}
.copyright {
color: #99999999;
font-size: 13px;
margin-left: 10px;
}
.description {
color: #676767;
}
.empty-access {
height: 220px;
margin-bottom: -20px;
}
.header {
align-items: center;
display: flex;
margin: 15px;
}
.logo {
height: 30px;
color: #999999;
width: 30px;
}
.title {
font-family: ProximaNova;
font-size: 21px;
font-weight: 600;
color: #444444;
}
</style>
</head>
<body>
<div class="header">
<svg class="logo" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 30 30" enable-background="new 0 0 30 30"
xml:space="preserve">
<g id="XMLID_17_">
<g id="XMLID_18_">
<g>
<g id="XMLID_225_">
<g id="XMLID_233_">
<path id="XMLID_234_" fill="#0080FF"
d="M15,30v-5.8c6.2,0,10.9-6.1,8.6-12.6c-0.9-2.4-2.8-4.3-5.2-5.2
C11.9,4.1,5.8,8.8,5.8,15l0,0L0,15C0,5.2,9.5-2.5,19.8,0.7c4.5,1.4,8.1,5,9.5,9.5C32.5,20.5,24.8,30,15,30z" />
</g>
<polygon id="XMLID_232_" fill="#0080FF" points="15,24.2 9.2,24.2 9.2,18.4 9.2,18.4 15,18.4 15,18.4" />
<polygon id="XMLID_228_" fill="#0080FF" points="9.2,28.7 4.8,28.7 4.8,28.7 4.8,24.2 9.2,24.2" />
<polygon id="XMLID_226_" fill="#0080FF" points="4.8,24.2 1,24.2 1,24.2 1,20.5 1,20.5 4.8,20.5 4.8,20.5" />
</g>
</g>
</g>
</g>
</svg>
<div class="copyright">&copy; 2023 DigitalOcean, LLC. All rights reserved.</div>
</div>
<div class="content">
<svg width="89" height="62" viewBox="0 0 89 62" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M78.4046 17.1912C84.738 21.1608 86.2188 20.7419 87.6794 19.9955C88.5202 19.5664 88.8496 18.5392 88.4243 17.6985C86.4622 13.818 78.212 0.118992 59.5364 0.118992C43.8588 0.118992 34.4377 13.3435 31.5684 18.0766C31.0067 19.0027 31.4447 20.2158 32.4755 20.5543C34.1357 21.0995 35.9508 21.216 39.8333 18.8625C52.5306 11.8038 78.4046 17.1912 78.4046 17.1912Z"
fill="#F15B55" />
<mask id="mask0_55_415" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="31" y="0" width="58" height="21">
<path
d="M78.4212 17.0723C84.7546 21.0418 86.2354 20.6229 87.696 19.8766C88.5368 19.4474 88.8662 18.4202 88.4409 17.5795C86.4788 13.699 78.2286 3.8147e-06 59.553 3.8147e-06C43.8754 3.8147e-06 34.4543 13.2245 31.585 17.9576C31.0233 18.8837 31.4613 20.0969 32.4921 20.4353C34.1523 20.9805 35.9674 21.097 39.8499 18.7436C52.5472 11.6848 78.4212 17.0723 78.4212 17.0723Z"
fill="#F15B55" />
</mask>
<g mask="url(#mask0_55_415)">
<path d="M43.7907 2.62413C49.4945 9.99967 33.5952 13.8544 45.8049 22.3539" stroke="#FF9580" stroke-width="1.5"
stroke-miterlimit="10" />
<path d="M56.7977 -1.62458C62.8837 6.0383 46.832 8.92189 53.8305 19.6981" stroke="#FF9580" stroke-width="1.5"
stroke-miterlimit="10" />
<path d="M72.3168 -0.867853C76.7291 7.02473 58.5477 8.73199 64.5571 18.3322" stroke="#FF9580" stroke-width="1.5"
stroke-miterlimit="10" />
<path d="M84.2603 7.02465C84.2603 15.1449 71.708 10.5128 72.3169 19.6982" stroke="#FF9580" stroke-width="1.5"
stroke-miterlimit="10" />
</g>
<g opacity="0.399994">
<g opacity="0.399994">
<path opacity="0.399994"
d="M31.3365 18.747C31.2415 19.5146 31.6815 20.2937 32.4751 20.5544C34.1353 21.0993 35.9508 21.2158 39.8333 18.8623C52.5302 11.8039 78.4042 17.1914 78.4042 17.1914C84.7377 21.1606 86.2184 20.7416 87.6795 19.9957C88.3903 19.6328 88.7337 18.8419 88.5657 18.0976C78.1555 10.8635 54.5866 3.8145 31.3365 18.747Z"
fill="black" />
</g>
</g>
<path
d="M67.274 14.8087H56.4204C44.6233 14.8087 38.4193 18.2775 33.8378 24.2005L29.4542 29.8671L27.7038 32.1805C26.3653 33.9491 24.2728 34.9885 22.0517 34.9885C18.6867 34.9885 15.8194 32.6685 15.0623 29.48C15.0512 29.433 15.0385 29.359 15.025 29.2679C14.9103 28.4884 15.5203 27.7899 16.3099 27.7899H18.4798C22.2049 27.7899 25.2246 24.7776 25.2246 21.0614V20.5325C25.2246 19.8467 24.667 19.2904 23.979 19.2904H17.6005C15.0492 19.2904 13.2669 20.6106 12.6674 22.0612C12.0676 20.6106 10.2853 19.2904 7.73397 19.2904H1.35542C0.667492 19.2904 0.109863 19.8467 0.109863 20.5325V21.0614C0.109863 24.7776 3.12951 27.7899 6.85471 27.7899H9.05492C9.75186 27.7899 10.3443 28.2988 10.4476 28.9867L10.6905 30.604C13.3361 48.2223 28.5057 61.2576 46.3638 61.2576H47.2697H59.4081C71.7445 61.2576 82.2727 52.3616 84.302 40.2227L85.8397 31.0254C87.259 22.5369 81.2902 14.8087 67.274 14.8087Z"
fill="#07CBCF" />
<path
d="M81.4705 48.3116C79.3404 48.386 77.5986 49.0698 75.2239 51.4388C72.2001 54.4552 67.1794 57.8702 59.4197 57.8702H45.0417C39.2224 57.8702 35.1162 53.5434 35.1162 53.5434C35.1162 53.5434 31.7479 53.7154 24.4261 49.5603C12.4254 41.9906 11.9501 29.2979 11.7788 27.7043C11.6076 26.1106 10.7517 25.2568 9.04025 25.2568H6.70074C2.34293 25.2568 1.16088 23.1183 0.893741 19.3792C0.434853 19.5628 0.110352 20.0095 0.110352 20.5327V21.0612C0.110352 24.7773 3.13 27.7897 6.85479 27.7897H9.055C9.75235 27.7897 10.3448 28.2986 10.4481 28.9864L10.6906 30.6038C13.3362 48.2221 28.5062 61.2573 46.3643 61.2573H47.2698H59.4086C68.7888 61.2573 77.1226 56.113 81.4705 48.3116Z"
fill="#05B7BF" />
<path
d="M15.0249 29.2677C14.9102 28.4883 15.5203 27.7898 16.3098 27.7898H18.4797C22.2049 27.7898 25.2246 24.7774 25.2246 21.0617V20.5328C25.2246 20.0092 24.8997 19.5624 24.4404 19.3793V19.3797C24.1728 23.1184 22.9908 25.2569 18.633 25.2569H16.8376C14.4411 25.2569 14.7549 27.9512 15.0249 29.2677Z"
fill="#05B7BF" />
<path
d="M24.4257 49.5606C27.1262 52.1789 25.7188 53.2412 21.2307 53.2412H14.3327C13.2428 53.2412 12.697 54.5557 13.4677 55.3245L14.322 56.1767C16.9737 58.8224 20.5707 60.3085 24.3213 60.3085H24.9584C32.4133 60.3085 37.929 52.8239 37.929 52.8239L24.4257 49.5606Z"
fill="#07CBCF" />
<path
d="M35.1162 53.544C32.9984 55.5574 29.4485 58.1536 25.2235 58.1536H24.6339C21.1631 58.1536 17.8345 56.7783 15.3807 54.33L14.59 53.5415C14.497 53.4488 14.4257 53.3474 14.3728 53.2411H14.3327C13.2428 53.2411 12.697 54.5556 13.4677 55.3244L14.322 56.1766C16.9741 58.8223 20.5711 60.3085 24.3213 60.3085H24.9584C29.8025 60.3085 33.8281 57.1482 36.0533 54.9349L36.3528 54.6312L35.1162 53.544Z"
fill="#05B7BF" />
<mask id="mask1_55_415" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="15" width="86" height="47">
<path
d="M67.1641 15.1884H56.3106C44.5134 15.1884 38.3094 18.6572 33.7279 24.5802L29.3443 30.2468L27.594 32.5602C26.2554 34.3288 24.163 35.3682 21.9419 35.3682C18.5768 35.3682 15.7096 33.0482 14.9524 29.8597C14.9413 29.8127 14.9286 29.7387 14.9151 29.6476C14.8004 28.8681 15.4105 28.1696 16.2 28.1696H18.3699C22.0951 28.1696 25.1147 25.1573 25.1147 21.4411V20.9122C25.1147 20.2264 24.5571 19.6701 23.8692 19.6701H17.4906C14.9393 19.6701 13.157 20.9903 12.5576 22.4409C11.9577 20.9903 10.1755 19.6701 7.62411 19.6701H1.24555C0.557629 19.6701 0 20.2264 0 20.9122V21.4411C0 25.1573 3.01965 28.1696 6.74484 28.1696H8.94506C9.64199 28.1696 10.2344 28.6785 10.3377 29.3664L10.5807 30.9837C13.2262 48.602 28.3958 61.6373 46.2539 61.6373H47.1598H59.2983C71.6346 61.6373 82.1628 52.7413 84.1922 40.6024L85.7299 31.4051C87.1491 22.9166 81.1803 15.1884 67.1641 15.1884Z"
fill="#07CBCF" />
</mask>
<g mask="url(#mask1_55_415)">
<path
d="M48.2573 43.0378C50.1929 48.5818 55.4426 52.9185 61.7015 52.9185C72.2568 52.9185 71.2993 45.7048 82.7326 45.7048H84.3526"
stroke="#00576C" stroke-width="1.46" stroke-miterlimit="10" stroke-linecap="round" />
<path d="M50.1195 43.0151H46.9814" stroke="#00576C" stroke-width="1.46" stroke-miterlimit="10"
stroke-linecap="round" />
<path
d="M65.353 42.7305C65.353 41.096 64.0247 39.7709 62.3862 39.7709C60.7478 39.7709 59.4194 41.096 59.4194 42.7305"
stroke="#00576C" stroke-width="1.46" stroke-miterlimit="10" stroke-linecap="round" />
</g>
<path
d="M77.4491 19.774C80.7847 21.9824 82.0434 23.4419 85.095 23.7701C82.9402 18.5919 77.0788 14.8087 67.2741 14.8087H56.4206C45.0819 14.8087 38.9111 18.0148 34.3804 23.5229C37.2443 23.5229 40.3812 21.1661 43.0628 19.698C46.182 17.9907 50.3669 16.3586 59.4197 16.3586C68.4725 16.3586 73.2651 17.004 77.4491 19.774Z"
fill="#05B7BF" />
</svg>
<h1 class="title">Please log into your Droplet with SSH to configure the Dokku installation.</h1>
<p class="description">See the Dokku 1-Click Quickstart guide for detailed assistance.</p>
<a class="button" href="https://do.co/dokku1804#start">Quickstart Guide</a>
</div>
</body>
</html>

View File

@@ -0,0 +1,47 @@
#!/bin/bash
set -eo pipefail
set -o errexit
export DEBIAN_FRONTEND=noninteractive
pkgs=(apt-transport-https
ca-certificates
curl
jq
linux-image-extra-virtual
software-properties-common
)
echo '--> Updating apt repositories'
apt-get -qqy update
echo '--> Updating all packages'
apt-get -qqy -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' full-upgrade
echo "--> Installing basic dependencies: ${pkgs[*]}"
apt-get -qqy install "${pkgs[@]}"
echo '--> Setting up docker apt repository'
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
cat >/etc/apt/sources.list.d/docker.list <<EOM
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -c -s) stable
EOM
echo '--> Installing docker-ce'
apt-get -y update
apt-get -y install docker-ce docker-compose-plugin
echo '--> Enabling docker-ce'
systemctl enable docker
systemctl start docker
echo '--> Enabling docker live-restore'
if [[ ! -f /etc/docker/daemon.json ]]; then
echo "{}" >/etc/docker/daemon.json
fi
config="$(jq '. + {"live-restore": true}' /etc/docker/daemon.json)"
echo "$config" >/etc/docker/daemon.json
systemctl reload docker
docker info | grep -i live

View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -eo pipefail
set -o errexit
echo '--> Prevent login until after setup is complete'
# Be a bit of a dork about login in
cat >>/etc/ssh/sshd_config <<EOM
Match User root
ForceCommand echo "Please wait while we get your droplet ready..."
EOM

View File

@@ -0,0 +1,66 @@
#!/bin/bash
set -eo pipefail
set -o errexit
export DEBIAN_FRONTEND=noninteractive
pkgs=(apache2-utils
bash-completion
locales
git
cpio
curl
man-db
netcat
net-tools
software-properties-common
parallel
python3-software-properties
rsync
rsyslog
dos2unix
jq
unzip
nginx
dnsutils
cgroupfs-mount
cgroup-lite
sudo
python3
debconf
)
dokku_pkgs=(docker-image-labeler
gliderlabs-sigil
lambda-builder
netrc
plugn
procfile-util
sshcommand
)
echo '--> Install core dependencies for dokku'
apt-get -y install "${pkgs[@]}"
echo '--> Setting up dokku apt repository'
curl -fsSL https://packagecloud.io/dokku/dokku/gpgkey -o /etc/apt/keyrings/dokku.asc
cat >/etc/apt/sources.list.d/dokku.list <<EOM
deb [arch=amd64 signed-by=/etc/apt/keyrings/dokku.asc] https://packagecloud.io/dokku/dokku/ubuntu/ bionic main
EOM
echo '--> Install dependencies for dokku from new repository'
apt-get -y clean
apt-get -y update
apt-get -y install "${dokku_pkgs[@]}"
rm -f /etc/nginx/sites-enabled/default
echo '--> Pre-cache dokku bits that are must run on boot'
apt-get -y clean
apt-get -y install --download-only "dokku=${DOKKU_VERSION}" dokku-event-listener herokuish
mkdir -p /var/lib/digitalocean/debs
cp -au /var/cache/apt/archives/*deb /var/lib/digitalocean/debs

View File

@@ -0,0 +1,9 @@
#!/bin/bash
set -eo pipefail
set -o errexit
echo '--> Update grub boot loader'
sed -e 's|GRUB_CMDLINE_LINUX="|GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1|g' \
-i /etc/default/grub
update-grub

View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -eo pipefail
set -o errexit
echo '--> Enable Google DNS for Docker'
sed -e 's|#DOCKER_OPTS|DOCKER_OPTS|g' \
-i /etc/default/docker

View File

@@ -0,0 +1,12 @@
#!/bin/bash
set -eo pipefail
set -o errexit
echo '--> Enable and configure UFW'
sed -e 's|DEFAULT_FORWARD_POLICY=.*|DEFAULT_FORWARD_POLICY="ACCEPT"|g' \
-i /etc/default/ufw
ufw limit ssh
ufw allow 'Nginx Full'
ufw --force enable

View File

@@ -0,0 +1,21 @@
#!/bin/bash
set -eo pipefail
set -o errexit
echo '--> Write the application info'
application_version="$DOKKU_VERSION"
build_date="$(date -I)"
distro_arch="$(uname -m)"
distro_codename="$(lsb_release -sc)"
distro_release="$(lsb_release -sr)"
distro="$(lsb_release -si)"
cat >/var/lib/digitalocean/application.info <<EOM
appiication_name="Dokku"
build_date="${build_date}"
distro="${distro}"
distro_release="${distro_release}"
distro_codename="${distro_codename}"
distro_arch="${distro_arch}"
application_version="${application_version}"
EOM

View File

@@ -0,0 +1,52 @@
#!/bin/bash
set -eo pipefail
set -o errexit
echo '--> Cleaning up tmp dir'
# Ensure /tmp exists and has the proper permissions before
# checking for security updates
# https://github.com/digitalocean/marketplace-partners/issues/94
if [[ ! -d /tmp ]]; then
mkdir /tmp
fi
chmod 1777 /tmp
rm -rf /tmp/* /var/tmp/*
echo '--> Cleaning up apt'
export DEBIAN_FRONTEND=noninteractive
apt-get -y update
apt-get -o Dpkg::Options::="--force-confold" upgrade -q -y --force-yes
apt-get -y autoremove
apt-get -y autoclean
apt-get -y purge droplet-agent
echo '--> Clearing history'
history -c
cat /dev/null >/root/.bash_history
unset HISTFILE
echo '--> Clearing log files'
find /var/log -mtime -1 -type f -exec truncate -s 0 {} \;
rm -rf /var/log/*.gz /var/log/*.[0-9] /var/log/*-????????
cat /dev/null >/var/log/lastlog
cat /dev/null >/var/log/wtmp
rm -rf /var/lib/cloud/instances/*
rm -rf /tmp/* /var/tmp/*
echo '--> Removing keys'
rm -f /root/.ssh/authorized_keys /etc/ssh/*key*
touch /etc/ssh/revoked_keys
chmod 600 /etc/ssh/revoked_keys
echo '--> DO Directory contents'
ls -lah /opt/digitalocean || true
echo '--> Securely erase the unused portion of the filesystem'
printf "\n\033[0;32mWriting zeros to the remaining disk space to securely
erase the unused portion of the file system.
Depending on your disk size this may take several minutes.
The secure erase will complete successfully when you see:\033[0m
dd: writing to '/zerofile': No space left on device\n
Beginning secure erase now\n"
dd if=/dev/zero of=/zerofile bs=4096 || rm /zerofile

View File

@@ -0,0 +1,636 @@
#!/bin/bash
# DigitalOcean Marketplace Image Validation Tool
# © 2021-2022 DigitalOcean LLC.
# This code is licensed under Apache 2.0 license (see LICENSE.md for details)
VERSION="v. 1.8.1"
RUNDATE=$(date)
# Script should be run with SUDO
if [ "$EUID" -ne 0 ]; then
echo "[Error] - This script must be run with sudo or as the root user."
exit 1
fi
STATUS=0
PASS=0
WARN=0
FAIL=0
# $1 == command to check for
# returns: 0 == true, 1 == false
cmdExists() {
if command -v "$1" >/dev/null 2>&1; then
return 0
else
return 1
fi
}
function getDistro {
if [ -f /etc/os-release ]; then
# freedesktop.org and systemd
# shellcheck disable=SC1091
. /etc/os-release
OS=$NAME
VER=$VERSION_ID
elif type lsb_release >/dev/null 2>&1; then
# linuxbase.org
OS=$(lsb_release -si)
VER=$(lsb_release -sr)
elif [ -f /etc/lsb-release ]; then
# For some versions of Debian/Ubuntu without lsb_release command
# shellcheck disable=SC1091
. /etc/lsb-release
OS=$DISTRIB_ID
VER=$DISTRIB_RELEASE
elif [ -f /etc/debian_version ]; then
# Older Debian/Ubuntu/etc.
OS=Debian
VER=$(cat /etc/debian_version)
elif [ -f /etc/SuSe-release ]; then
# Older SuSE/etc.
:
elif [ -f /etc/redhat-release ]; then
# Older Red Hat, CentOS, etc.
VER=$(cut -d" " -f3 </etc/redhat-release | cut -d "." -f1)
d=$(cut -d" " -f1 </etc/redhat-release | cut -d "." -f1)
if [[ $d == "CentOS" ]]; then
OS="CentOS Linux"
fi
else
# Fall back to uname, e.g. "Linux <version>", also works for BSD, etc.
OS=$(uname -s)
VER=$(uname -r)
fi
}
function loadPasswords {
SHADOW=$(cat /etc/shadow)
}
function checkAgent {
# Check for the presence of the DO directory in the filesystem
if [ -d /opt/digitalocean ]; then
echo -en "\e[41m[FAIL]\e[0m DigitalOcean directory detected.\n"
((FAIL++))
STATUS=2
if [[ $OS == "CentOS Linux" ]] || [[ $OS == "CentOS Stream" ]] || [[ $OS == "Rocky Linux" ]] || [[ $OS == "AlmaLinux" ]]; then
echo "To uninstall the agent: 'sudo yum remove droplet-agent'"
echo "To remove the DO directory: 'find /opt/digitalocean/ -type d -empty -delete'"
elif [[ $OS == "Ubuntu" ]] || [[ $OS == "Debian" ]]; then
echo "To uninstall the agent and remove the DO directory: 'sudo apt-get purge droplet-agent'"
fi
else
echo -en "\e[32m[PASS]\e[0m DigitalOcean Monitoring agent was not found\n"
((PASS++))
fi
}
function checkLogs {
cp_ignore="/var/log/cpanel-install.log"
echo -en "\nChecking for log files in /var/log\n\n"
# Check if there are log archives or log files that have not been recently cleared.
for f in /var/log/*-????????; do
[[ -e $f ]] || break
if [ "${f}" != "${cp_ignore}" ]; then
echo -en "\e[93m[WARN]\e[0m Log archive ${f} found; Contents:\n"
cat "${f}"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
done
for f in /var/log/*.[0-9]; do
[[ -e $f ]] || break
echo -en "\e[93m[WARN]\e[0m Log archive ${f} found; Contents:\n"
cat "${f}"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
done
for f in /var/log/*.log; do
[[ -e $f ]] || break
if [[ "${f}" = '/var/log/lfd.log' && "$(grep -E -v '/var/log/messages has been reset| Watching /var/log/messages' "${f}" | wc -c)" -gt 50 ]]; then
if [ "${f}" != "${cp_ignore}" ]; then
echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found; Contents:\n"
cat "${f}"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
elif [[ "${f}" != '/var/log/lfd.log' && "$(wc -c <"${f}")" -gt 50 ]]; then
if [ "${f}" != "${cp_ignore}" ]; then
echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found; Contents:\n"
cat "${f}"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
fi
done
}
function checkTMP {
# Check the /tmp directory to ensure it is empty. Warn on any files found.
if [[ -n "$(ls -A /tmp)" ]]; then
echo -en "\e[93m[WARN]\e[0m /tmp directory is not empty; Contents\n"
ls -A /tmp
((WARN++))
return 1
fi
echo -en "\e[32m[PASS]\e[0m /tmp directory is empty\n"
return 0
}
function checkRoot {
user="root"
uhome="/root"
for usr in $SHADOW; do
IFS=':' read -r -a u <<<"$usr"
if [[ "${u[0]}" == "${user}" ]]; then
if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then
echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n"
((PASS++))
else
echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account.\n"
((FAIL++))
STATUS=2
fi
fi
done
if [ -d ${uhome}/ ]; then
if [ -d ${uhome}/.ssh/ ]; then
if ls ${uhome}/.ssh/* >/dev/null 2>&1; then
for key in "${uhome}"/.ssh/*; do
if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then
if [ "$(wc -c <"${key}")" -gt 50 ]; then
echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n"
akey=$(cat "${key}")
echo "File Contents:"
echo "$akey"
echo "--------------"
((FAIL++))
STATUS=2
fi
elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then
if [ "$(wc -c <"${key}")" -gt 0 ]; then
echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n"
akey=$(cat "${key}")
echo "File Contents:"
echo "$akey"
echo "--------------"
((FAIL++))
STATUS=2
else
echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then
echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory at \e[93m${key}\e[0m\n"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
else
if [ "$(wc -c <"${key}")" -gt 50 ]; then
echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a populated known_hosts file in \e[93m${key}\e[0m\n"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
fi
done
else
echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n"
fi
else
echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n"
fi
if [ -f /root/.bash_history ]; then
BH_S=$(wc -c </root/.bash_history)
if [[ $BH_S -lt 200 ]]; then
echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n"
((PASS++))
else
echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n"
((FAIL++))
STATUS=2
fi
return 1
else
echo -en "\e[32m[PASS]\e[0m The Root User's Bash History is not present\n"
((PASS++))
fi
else
echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n"
fi
echo -en "\n\n"
return 1
}
function checkUsers {
# Check each user-created account
awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' </etc/passwd | while IFS= read -r user; do
# Skip some other non-user system accounts
if [[ $user == "centos" ]]; then
:
elif [[ $user == "nfsnobody" ]]; then
:
else
echo -en "\nChecking user: ${user}...\n"
for usr in $SHADOW; do
IFS=':' read -r -a u <<<"$usr"
if [[ "${u[0]}" == "${user}" ]]; then
if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then
echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n"
# shellcheck disable=SC2030
((PASS++))
else
echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account. Only system users are allowed on the image.\n"
# shellcheck disable=SC2030
((FAIL++))
STATUS=2
fi
fi
done
#echo "User Found: ${user}"
uhome="/home/${user}"
if [ -d "${uhome}/" ]; then
if [ -d "${uhome}/.ssh/" ]; then
if ls "${uhome}/.ssh/*" >/dev/null 2>&1; then
for key in "${uhome}"/.ssh/*; do
if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then
if [ "$(wc -c <"${key}")" -gt 50 ]; then
echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n"
akey=$(cat "${key}")
echo "File Contents:"
echo "$akey"
echo "--------------"
((FAIL++))
STATUS=2
fi
elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then
if [ "$(wc -c <"${key}")" -gt 0 ]; then
echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n"
akey=$(cat "${key}")
echo "File Contents:"
echo "$akey"
echo "--------------"
((FAIL++))
STATUS=2
else
echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n"
# shellcheck disable=SC2030
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then
echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory named \e[93m${key}\e[0m\n"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
else
if [ "$(wc -c <"${key}")" -gt 50 ]; then
echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a known_hosts file in \e[93m${key}\e[0m\n"
((WARN++))
if [[ $STATUS != 2 ]]; then
STATUS=1
fi
fi
fi
done
else
echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n"
fi
else
echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n"
fi
else
echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n"
fi
# Check for an uncleared .bash_history for this user
if [ -f "${uhome}/.bash_history" ]; then
BH_S=$(wc -c <"${uhome}/.bash_history")
if [[ $BH_S -lt 200 ]]; then
echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n"
((PASS++))
else
echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n"
((FAIL++))
STATUS=2
fi
echo -en "\n\n"
fi
fi
done
}
function checkFirewall {
if [[ $OS == "Ubuntu" ]]; then
fw="ufw"
ufwa=$(ufw status | head -1 | sed -e "s/^Status:\ //")
if [[ $ufwa == "active" ]]; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
# shellcheck disable=SC2031
((PASS++))
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
# shellcheck disable=SC2031
((WARN++))
fi
elif [[ $OS == "CentOS Linux" ]] || [[ $OS == "CentOS Stream" ]] || [[ $OS == "Rocky Linux" ]] || [[ $OS == "AlmaLinux" ]]; then
if [ -f /usr/lib/systemd/system/csf.service ]; then
fw="csf"
if [[ $(systemctl status $fw >/dev/null 2>&1) ]]; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
((PASS++))
elif cmdExists "firewall-cmd"; then
if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
((PASS++))
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
((WARN++))
fi
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
((WARN++))
fi
else
fw="firewalld"
if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
((PASS++))
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
((WARN++))
fi
fi
elif [[ "$OS" =~ Debian.* ]]; then
# user could be using a number of different services for managing their firewall
# we will check some of the most common
if cmdExists 'ufw'; then
fw="ufw"
ufwa=$(ufw status | head -1 | sed -e "s/^Status:\ //")
if [[ $ufwa == "active" ]]; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
((PASS++))
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
((WARN++))
fi
elif cmdExists "firewall-cmd"; then
fw="firewalld"
if [[ $(systemctl is-active --quiet $fw) ]]; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
((PASS++))
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
((WARN++))
fi
else
# user could be using vanilla iptables, check if kernel module is loaded
fw="iptables"
if lsmod | grep -q '^ip_tables' 2>/dev/null; then
FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n"
((PASS++))
else
FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n"
((WARN++))
fi
fi
fi
}
function checkUpdates {
if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then
# Ensure /tmp exists and has the proper permissions before
# checking for security updates
# https://github.com/digitalocean/marketplace-partners/issues/94
if [[ ! -d /tmp ]]; then
mkdir /tmp
fi
chmod 1777 /tmp
echo -en "\nUpdating apt package database to check for security updates, this may take a minute...\n\n"
apt-get -y update >/dev/null
uc=$(apt-get --just-print upgrade | grep -i "security" -c)
if [[ $uc -gt 0 ]]; then
update_count=$((uc / 2))
else
update_count=0
fi
if [[ $update_count -gt 0 ]]; then
echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n"
echo -en
echo -en "Here is a list of the security updates that are not installed:\n"
sleep 2
apt-get --just-print upgrade | grep -i security | awk '{print $2}' | awk '!seen[$0]++'
echo -en
# shellcheck disable=SC2031
((FAIL++))
STATUS=2
else
echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n\n"
((PASS++))
fi
elif [[ $OS == "CentOS Linux" ]] || [[ $OS == "CentOS Stream" ]] || [[ $OS == "Rocky Linux" ]] || [[ $OS == "AlmaLinux" ]]; then
echo -en "\nChecking for available security updates, this may take a minute...\n\n"
update_count=$(yum check-update --security --quiet | wc -l)
if [[ $update_count -gt 0 ]]; then
echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n"
((FAIL++))
STATUS=2
else
echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n"
((PASS++))
fi
else
echo "Error encountered"
exit 1
fi
return 1
}
function checkCloudInit {
if hash cloud-init 2>/dev/null; then
CI="\e[32m[PASS]\e[0m Cloud-init is installed.\n"
((PASS++))
else
CI="\e[41m[FAIL]\e[0m No valid verison of cloud-init was found.\n"
((FAIL++))
STATUS=2
fi
return 1
}
clear
echo "DigitalOcean Marketplace Image Validation Tool ${VERSION}"
echo "Executed on: ${RUNDATE}"
echo "Checking local system for Marketplace compatibility..."
getDistro
echo -en "\n\e[1mDistribution:\e[0m ${OS}\n"
echo -en "\e[1mVersion:\e[0m ${VER}\n\n"
ost=0
osv=0
if [[ $OS == "Ubuntu" ]]; then
ost=1
if [[ $VER == "22.10" ]] || [[ $VER == "22.04" ]] || [[ $VER == "20.04" ]] || [[ $VER == "18.04" ]] || [[ $VER == "16.04" ]]; then
osv=1
fi
elif [[ "$OS" =~ Debian.* ]]; then
ost=1
case "$VER" in
9)
osv=1
;;
10)
osv=1
;;
11)
osv=1
;;
*)
osv=2
;;
esac
elif [[ $OS == "CentOS Linux" ]]; then
ost=1
if [[ $VER == "8" ]]; then
osv=1
elif [[ $VER == "7" ]]; then
osv=1
elif [[ $VER == "6" ]]; then
osv=1
else
osv=2
fi
elif [[ $OS == "CentOS Stream" ]]; then
ost=1
if [[ $VER == "8" ]]; then
osv=1
else
osv=2
fi
elif [[ $OS == "Rocky Linux" ]]; then
ost=1
if [[ $VER =~ 8\. ]]; then
osv=1
else
osv=2
fi
elif [[ $OS == "AlmaLinux" ]]; then
ost=1
if [[ "$VERSION" =~ 8.* ]] || [[ "$VERSION" =~ 9.* ]]; then
osv=1
else
osv=2
fi
else
ost=0
fi
if [[ $ost == 1 ]]; then
echo -en "\e[32m[PASS]\e[0m Supported Operating System Detected: ${OS}\n"
((PASS++))
else
echo -en "\e[41m[FAIL]\e[0m ${OS} is not a supported Operating System\n"
((FAIL++))
STATUS=2
fi
if [[ $osv == 1 ]]; then
echo -en "\e[32m[PASS]\e[0m Supported Release Detected: ${VER}\n"
((PASS++))
elif [[ $ost == 1 ]]; then
echo -en "\e[41m[FAIL]\e[0m ${OS} ${VER} is not a supported Operating System Version\n"
((FAIL++))
STATUS=2
else
echo "Exiting..."
exit 1
fi
checkCloudInit
echo -en "${CI}"
checkFirewall
echo -en "${FW_VER}"
checkUpdates
loadPasswords
checkLogs
echo -en "\n\nChecking all user-created accounts...\n"
checkUsers
echo -en "\n\nChecking the root account...\n"
checkRoot
echo -en "\n\nChecking the /tmp directory...\n"
checkTMP
checkAgent
# Summary
echo -en "\n\n---------------------------------------------------------------------------------------------------\n"
if [[ $STATUS == 0 ]]; then
echo -en "Scan Complete.\n\e[32mAll Tests Passed!\e[0m\n"
elif [[ $STATUS == 1 ]]; then
echo -en "Scan Complete. \n\e[93mSome non-critical tests failed. Please review these items.\e[0m\e[0m\n"
else
echo -en "Scan Complete. \n\e[41mOne or more tests failed. Please review these items and re-test.\e[0m\n"
fi
echo "---------------------------------------------------------------------------------------------------"
echo -en "\e[1m${PASS} Tests PASSED\e[0m\n"
echo -en "\e[1m${WARN} WARNINGS\e[0m\n"
echo -en "\e[1m${FAIL} Tests FAILED\e[0m\n"
echo -en "---------------------------------------------------------------------------------------------------\n"
if [[ $STATUS == 0 ]]; then
echo -en "We did not detect any issues with this image. Please be sure to manually ensure that all software installed on the base system is functional, secure and properly configured (or facilities for configuration on first-boot have been created).\n\n"
exit 0
elif [[ $STATUS == 1 ]]; then
echo -en "Please review all [WARN] items above and ensure they are intended or resolved. If you do not have a specific requirement, we recommend resolving these items before image submission\n\n"
exit 0
else
echo -en "Some critical tests failed. These items must be resolved and this scan re-run before you submit your image to the DigitalOcean Marketplace.\n\n"
exit 1
fi

View File

@@ -0,0 +1,70 @@
packer {
required_plugins {
digitalocean = {
version = ">= 1.0.4"
source = "github.com/digitalocean/digitalocean"
}
}
}
variable "dokku_version" {
type = string
}
source "digitalocean" "ubuntu" {
image = "ubuntu-22-04-x64"
region = "nyc1"
size = "s-1vcpu-512mb-10gb"
ssh_username = "root"
snapshot_name = "dokku-${var.dokku_version}-snapshot-{{timestamp}}"
}
build {
name = "dokku"
sources = [
"source.digitalocean.ubuntu"
]
provisioner "shell" {
inline = [
"echo '--> Waiting until cloud-init is complete'",
"/usr/bin/cloud-init status --wait",
]
}
provisioner "file" {
source = "${path.root}/files/etc/"
destination = "/etc/"
}
provisioner "file" {
source = "${path.root}/files/var/"
destination = "/var/"
}
provisioner "shell" {
environment_vars = [
"DOKKU_VERSION=${var.dokku_version}",
"DEBIAN_FRONTEND=noninteractive",
"LC_ALL=C",
"LANG=en_US.UTF-8",
"LC_CTYPE=en_US.UTF-8",
]
scripts = [
"${path.root}/in_parts/011-docker",
"${path.root}/in_parts/011-ssh-message",
"${path.root}/in_parts/012-dokku-packages",
"${path.root}/in_parts/012-grub-opts",
"${path.root}/in_parts/014-docker-dns",
"${path.root}/in_parts/014-ufw-rules",
"${path.root}/in_parts/099-application_tag",
"${path.root}/in_parts/099-cleanup",
"${path.root}/in_parts/100-image-check",
]
}
post-processor "manifest" {
output = "digitalocean-manifest.json"
}
}

View File

@@ -1,32 +0,0 @@
{
"builders": [
{
"type": "digitalocean",
"region": "nyc3",
"image": "ubuntu-14-04-x64"
}
],
"provisioners": [
{
"type": "file",
"source": "deb.mk",
"destination": "/tmp/Makefile"
},
{
"type": "shell",
"inline": [
"echo '--> Waiting 30 seconds for core services to be available'",
"sleep 30",
"echo '--> Updating apt repositories'",
"sudo apt-get update -qq >/dev/null",
"echo '--> Installing make requirement'",
"sudo apt-get -qq -y --no-install-recommends install build-essential",
"cd /tmp && make install-from-deb",
"rm /root/.ssh/authorized_keys"
]
}
]
}

View File

@@ -1,3 +1,7 @@
ifndef PKR_VAR_dokku_version
PKR_VAR_dokku_version = $(shell grep Version debian/control | cut -d' ' -f2)
endif
/tmp/build-dokku/var/lib/dokku/GIT_REV:
mkdir -p /tmp/build-dokku
mkdir -p /tmp/build-dokku/usr/share/bash-completion/completions
@@ -31,3 +35,15 @@ ifdef DOKKU_GIT_REV
else
git rev-parse HEAD > /tmp/build-dokku/var/lib/dokku/GIT_REV
endif
.PHONY: image/build/digitalocean
image/build/digitalocean:
packer build -var 'dokku_version=${PKR_VAR_dokku_version}' contrib/images/digitalocean/packer.pkr.hcl
.PHONY: image/init/digitalocean
image/init/digitalocean:
packer init contrib/images/digitalocean/packer.pkr.hcl
.PHONY: image/validate/digitalocean
image/validate/digitalocean:
packer validate -var 'dokku_version=${PKR_VAR_dokku_version}' contrib/images/digitalocean/packer.pkr.hcl