handle deployment config updates
This commit is contained in:
@@ -50,7 +50,7 @@ function django_setup {
|
|||||||
|
|
||||||
DJANGO_SEKRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 80 | head -n 1)
|
DJANGO_SEKRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 80 | head -n 1)
|
||||||
|
|
||||||
BASE_DOMAIN=$(echo "$APP_HOST" | awk -F. '{print $(NF-1)"."$NF}')
|
BASE_DOMAIN=$(echo "import tldextract; no_fetch_extract = tldextract.TLDExtract(suffix_list_urls=()); extracted = no_fetch_extract('${API_HOST}'); print(f'{extracted.domain}.{extracted.suffix}')" | python)
|
||||||
|
|
||||||
localvars="$(
|
localvars="$(
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
@@ -72,15 +72,12 @@ ADMIN_URL = 'admin/'
|
|||||||
ALLOWED_HOSTS = ['${API_HOST}', '${APP_HOST}', '*']
|
ALLOWED_HOSTS = ['${API_HOST}', '${APP_HOST}', '*']
|
||||||
|
|
||||||
CORS_ORIGIN_WHITELIST = ['https://${APP_HOST}']
|
CORS_ORIGIN_WHITELIST = ['https://${APP_HOST}']
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
|
||||||
|
|
||||||
SESSION_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
SESSION_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
||||||
CSRF_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
CSRF_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
||||||
CSRF_TRUSTED_ORIGINS = ['https://${API_HOST}', 'https://${APP_HOST}']
|
CSRF_TRUSTED_ORIGINS = ['https://${API_HOST}', 'https://${APP_HOST}']
|
||||||
|
|
||||||
HEADLESS_FRONTEND_URLS = {
|
HEADLESS_FRONTEND_URLS = {'socialaccount_login_error': 'https://${APP_HOST}/account/provider/callback'}
|
||||||
'socialaccount_login_error': 'https://${APP_HOST}/account/provider/callback'
|
|
||||||
}
|
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
|
@@ -17,6 +17,12 @@ class Command(BaseCommand):
|
|||||||
match kwargs["name"]:
|
match kwargs["name"]:
|
||||||
case "api":
|
case "api":
|
||||||
self.stdout.write(settings.ALLOWED_HOSTS[0])
|
self.stdout.write(settings.ALLOWED_HOSTS[0])
|
||||||
|
case "rootdomain":
|
||||||
|
import tldextract
|
||||||
|
|
||||||
|
no_fetch_extract = tldextract.TLDExtract(suffix_list_urls=())
|
||||||
|
extracted = no_fetch_extract(settings.ALLOWED_HOSTS[0])
|
||||||
|
self.stdout.write(f"{extracted.domain}.{extracted.suffix}")
|
||||||
case "version":
|
case "version":
|
||||||
self.stdout.write(settings.TRMM_VERSION)
|
self.stdout.write(settings.TRMM_VERSION)
|
||||||
case "webversion":
|
case "webversion":
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
import base64
|
import base64
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
from accounts.models import User
|
from accounts.models import User
|
||||||
@@ -10,6 +14,7 @@ from core.models import CoreSettings
|
|||||||
from core.tasks import remove_orphaned_history_results, sync_mesh_perms_task
|
from core.tasks import remove_orphaned_history_results, sync_mesh_perms_task
|
||||||
from scripts.models import Script
|
from scripts.models import Script
|
||||||
from tacticalrmm.constants import AGENT_DEFER, ScriptType
|
from tacticalrmm.constants import AGENT_DEFER, ScriptType
|
||||||
|
from tacticalrmm.helpers import get_webdomain
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@@ -18,6 +23,37 @@ class Command(BaseCommand):
|
|||||||
def handle(self, *args, **kwargs) -> None:
|
def handle(self, *args, **kwargs) -> None:
|
||||||
self.stdout.write("Running post update tasks")
|
self.stdout.write("Running post update tasks")
|
||||||
|
|
||||||
|
# for 0.20.0 release
|
||||||
|
if not settings.DOCKER_BUILD:
|
||||||
|
needs_frontend = False
|
||||||
|
frontend_domain = get_webdomain().split(":")[0]
|
||||||
|
|
||||||
|
local_settings = os.path.join(
|
||||||
|
settings.BASE_DIR, "tacticalrmm", "local_settings.py"
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(local_settings) as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
modified_lines = []
|
||||||
|
for line in lines:
|
||||||
|
if line.strip().startswith("ALLOWED_HOSTS"):
|
||||||
|
exec(line, globals())
|
||||||
|
|
||||||
|
if frontend_domain not in settings.ALLOWED_HOSTS:
|
||||||
|
needs_frontend = True
|
||||||
|
settings.ALLOWED_HOSTS.append(frontend_domain)
|
||||||
|
|
||||||
|
line = f"ALLOWED_HOSTS = {settings.ALLOWED_HOSTS}\n"
|
||||||
|
|
||||||
|
modified_lines.append(line)
|
||||||
|
|
||||||
|
if needs_frontend:
|
||||||
|
backup = Path.home() / (Path("local_settings_0.20.0.bak"))
|
||||||
|
shutil.copy2(local_settings, backup)
|
||||||
|
with open(local_settings, "w") as f:
|
||||||
|
f.writelines(modified_lines)
|
||||||
|
|
||||||
# load community scripts into the db
|
# load community scripts into the db
|
||||||
Script.load_community_scripts()
|
Script.load_community_scripts()
|
||||||
|
|
||||||
|
@@ -5,10 +5,8 @@ For details, see: https://license.tacticalrmm.com/ee
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from time import sleep
|
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import requests
|
|
||||||
from core.models import CodeSignToken
|
from core.models import CodeSignToken
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
@@ -26,39 +24,12 @@ class Command(BaseCommand):
|
|||||||
self.stdout.write(url)
|
self.stdout.write(url)
|
||||||
return
|
return
|
||||||
|
|
||||||
attempts = 0
|
if t.is_valid:
|
||||||
while 1:
|
|
||||||
try:
|
|
||||||
r = requests.post(
|
|
||||||
settings.REPORTING_CHECK_URL,
|
|
||||||
json={"token": t.token, "api": settings.ALLOWED_HOSTS[0]},
|
|
||||||
headers={"Content-type": "application/json"},
|
|
||||||
timeout=15,
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
self.stderr.write(str(e))
|
|
||||||
attempts += 1
|
|
||||||
sleep(3)
|
|
||||||
else:
|
|
||||||
if r.status_code // 100 in (3, 5):
|
|
||||||
self.stderr.write(f"Error getting web tarball: {r.status_code}")
|
|
||||||
attempts += 1
|
|
||||||
sleep(3)
|
|
||||||
else:
|
|
||||||
attempts = 0
|
|
||||||
|
|
||||||
if attempts == 0:
|
|
||||||
break
|
|
||||||
elif attempts > 5:
|
|
||||||
self.stdout.write(url)
|
|
||||||
return
|
|
||||||
|
|
||||||
if r.status_code == 200: # type: ignore
|
|
||||||
params = {
|
params = {
|
||||||
"token": t.token,
|
"token": t.token,
|
||||||
"webver": settings.WEB_VERSION,
|
"webver": settings.WEB_VERSION,
|
||||||
"api": settings.ALLOWED_HOSTS[0],
|
"api": settings.ALLOWED_HOSTS[0],
|
||||||
}
|
}
|
||||||
url = settings.REPORTING_DL_URL + urllib.parse.urlencode(params)
|
url = settings.WEBTAR_DL_URL + urllib.parse.urlencode(params)
|
||||||
|
|
||||||
self.stdout.write(url)
|
self.stdout.write(url)
|
||||||
|
@@ -16,3 +16,4 @@ SOCIALACCOUNT_EMAIL_VERIFICATION = True
|
|||||||
SOCIALACCOUNT_PROVIDERS = {"openid_connect": {"OAUTH_PKCE_ENABLED": True}}
|
SOCIALACCOUNT_PROVIDERS = {"openid_connect": {"OAUTH_PKCE_ENABLED": True}}
|
||||||
|
|
||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
|
@@ -30,6 +30,7 @@ redis==5.0.8
|
|||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
sqlparse==0.5.1
|
sqlparse==0.5.1
|
||||||
|
tldextract==5.1.2
|
||||||
twilio==8.13.0
|
twilio==8.13.0
|
||||||
urllib3==2.2.3
|
urllib3==2.2.3
|
||||||
uvicorn[standard]==0.31.1
|
uvicorn[standard]==0.31.1
|
||||||
|
@@ -126,8 +126,7 @@ with suppress(ImportError):
|
|||||||
CHECK_TOKEN_URL = f"{AGENT_BASE_URL}/api/v2/checktoken"
|
CHECK_TOKEN_URL = f"{AGENT_BASE_URL}/api/v2/checktoken"
|
||||||
AGENTS_URL = f"{AGENT_BASE_URL}/api/v2/agents/?"
|
AGENTS_URL = f"{AGENT_BASE_URL}/api/v2/agents/?"
|
||||||
EXE_GEN_URL = f"{AGENT_BASE_URL}/api/v2/exe"
|
EXE_GEN_URL = f"{AGENT_BASE_URL}/api/v2/exe"
|
||||||
REPORTING_CHECK_URL = f"{AGENT_BASE_URL}/api/v2/reporting/check"
|
WEBTAR_DL_URL = f"{AGENT_BASE_URL}/api/v2/webtar/?"
|
||||||
REPORTING_DL_URL = f"{AGENT_BASE_URL}/api/v2/reporting/download/?"
|
|
||||||
|
|
||||||
if "GHACTIONS" in os.environ:
|
if "GHACTIONS" in os.environ:
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
@@ -71,6 +71,7 @@ if [ "$1" = 'tactical-init' ]; then
|
|||||||
MESH_TOKEN=$(cat ${TACTICAL_DIR}/tmp/mesh_token)
|
MESH_TOKEN=$(cat ${TACTICAL_DIR}/tmp/mesh_token)
|
||||||
ADMINURL=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 70 | head -n 1)
|
ADMINURL=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 70 | head -n 1)
|
||||||
DJANGO_SEKRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 80 | head -n 1)
|
DJANGO_SEKRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 80 | head -n 1)
|
||||||
|
BASE_DOMAIN=$(echo "import tldextract; no_fetch_extract = tldextract.TLDExtract(suffix_list_urls=()); extracted = no_fetch_extract('${API_HOST}'); print(f'{extracted.domain}.{extracted.suffix}')" | python)
|
||||||
|
|
||||||
localvars="$(
|
localvars="$(
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
@@ -93,15 +94,12 @@ ALLOWED_HOSTS = ['${API_HOST}', '${APP_HOST}', 'tactical-backend']
|
|||||||
ADMIN_URL = '${ADMINURL}/'
|
ADMIN_URL = '${ADMINURL}/'
|
||||||
|
|
||||||
CORS_ORIGIN_WHITELIST = ['https://${APP_HOST}']
|
CORS_ORIGIN_WHITELIST = ['https://${APP_HOST}']
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
|
||||||
|
|
||||||
SESSION_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
SESSION_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
||||||
CSRF_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
CSRF_COOKIE_DOMAIN = '${BASE_DOMAIN}'
|
||||||
CSRF_TRUSTED_ORIGINS = ['https://${API_HOST}', 'https://${APP_HOST}']
|
CSRF_TRUSTED_ORIGINS = ['https://${API_HOST}', 'https://${APP_HOST}']
|
||||||
|
|
||||||
HEADLESS_FRONTEND_URLS = {
|
HEADLESS_FRONTEND_URLS = {'socialaccount_login_error': 'https://${APP_HOST}/account/provider/callback'}
|
||||||
'socialaccount_login_error': 'https://${APP_HOST}/account/provider/callback'
|
|
||||||
}
|
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
|
13
install.sh
13
install.sh
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
SCRIPT_VERSION="86"
|
SCRIPT_VERSION="87"
|
||||||
SCRIPT_URL="https://raw.githubusercontent.com/amidaware/tacticalrmm/master/install.sh"
|
SCRIPT_URL="https://raw.githubusercontent.com/amidaware/tacticalrmm/master/install.sh"
|
||||||
|
|
||||||
sudo apt install -y curl wget dirmngr gnupg lsb-release ca-certificates
|
sudo apt install -y curl wget dirmngr gnupg lsb-release ca-certificates
|
||||||
@@ -570,6 +570,7 @@ python manage.py load_chocos
|
|||||||
python manage.py load_community_scripts
|
python manage.py load_community_scripts
|
||||||
WEB_VERSION=$(python manage.py get_config webversion)
|
WEB_VERSION=$(python manage.py get_config webversion)
|
||||||
WEBTAR_URL=$(python manage.py get_webtar_url)
|
WEBTAR_URL=$(python manage.py get_webtar_url)
|
||||||
|
ROOT_DOMAIN=$(python manage.py get_config rootdomain)
|
||||||
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
|
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
|
||||||
printf >&2 "\n"
|
printf >&2 "\n"
|
||||||
printf >&2 "${YELLOW}Please create your login for the RMM website${NC}\n"
|
printf >&2 "${YELLOW}Please create your login for the RMM website${NC}\n"
|
||||||
@@ -585,6 +586,16 @@ python manage.py generate_barcode ${RANDBASE} ${djangousername} ${frontenddomain
|
|||||||
deactivate
|
deactivate
|
||||||
read -n 1 -s -r -p "Press any key to continue..."
|
read -n 1 -s -r -p "Press any key to continue..."
|
||||||
|
|
||||||
|
allauth="$(
|
||||||
|
cat <<EOF
|
||||||
|
SESSION_COOKIE_DOMAIN = '${ROOT_DOMAIN}'
|
||||||
|
CSRF_COOKIE_DOMAIN = '${ROOT_DOMAIN}'
|
||||||
|
CSRF_TRUSTED_ORIGINS = ["https://${frontenddomain}", "https://${rmmdomain}"]
|
||||||
|
HEADLESS_FRONTEND_URLS = {"socialaccount_login_error": "https://${frontenddomain}/account/provider/callback"}
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
echo "${allauth}" | tee --append $local_settings >/dev/null
|
||||||
|
|
||||||
rmmservice="$(
|
rmmservice="$(
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
|
24
restore.sh
24
restore.sh
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
SCRIPT_VERSION="60"
|
SCRIPT_VERSION="61"
|
||||||
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/restore.sh'
|
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/restore.sh'
|
||||||
|
|
||||||
sudo apt update
|
sudo apt update
|
||||||
@@ -15,6 +15,7 @@ NC='\033[0m'
|
|||||||
SCRIPTS_DIR='/opt/trmm-community-scripts'
|
SCRIPTS_DIR='/opt/trmm-community-scripts'
|
||||||
PYTHON_VER='3.11.8'
|
PYTHON_VER='3.11.8'
|
||||||
SETTINGS_FILE='/rmm/api/tacticalrmm/tacticalrmm/settings.py'
|
SETTINGS_FILE='/rmm/api/tacticalrmm/tacticalrmm/settings.py'
|
||||||
|
local_settings='/rmm/api/tacticalrmm/tacticalrmm/local_settings.py'
|
||||||
|
|
||||||
TMP_FILE=$(mktemp -p "" "rmmrestore_XXXXXXXXXX")
|
TMP_FILE=$(mktemp -p "" "rmmrestore_XXXXXXXXXX")
|
||||||
curl -s -L "${SCRIPT_URL}" >${TMP_FILE}
|
curl -s -L "${SCRIPT_URL}" >${TMP_FILE}
|
||||||
@@ -445,8 +446,8 @@ sudo chmod +x /usr/local/bin/nats-api
|
|||||||
|
|
||||||
print_green 'Restoring the trmm database'
|
print_green 'Restoring the trmm database'
|
||||||
|
|
||||||
pgusername=$(grep -w USER /rmm/api/tacticalrmm/tacticalrmm/local_settings.py | sed 's/^.*: //' | sed 's/.//' | sed -r 's/.{2}$//')
|
pgusername=$(grep -w USER $local_settings | sed 's/^.*: //' | sed 's/.//' | sed -r 's/.{2}$//')
|
||||||
pgpw=$(grep -w PASSWORD /rmm/api/tacticalrmm/tacticalrmm/local_settings.py | sed 's/^.*: //' | sed 's/.//' | sed -r 's/.{2}$//')
|
pgpw=$(grep -w PASSWORD $local_settings | sed 's/^.*: //' | sed 's/.//' | sed -r 's/.{2}$//')
|
||||||
|
|
||||||
sudo -iu postgres psql -c "CREATE DATABASE tacticalrmm"
|
sudo -iu postgres psql -c "CREATE DATABASE tacticalrmm"
|
||||||
sudo -iu postgres psql -c "CREATE USER ${pgusername} WITH PASSWORD '${pgpw}'"
|
sudo -iu postgres psql -c "CREATE USER ${pgusername} WITH PASSWORD '${pgpw}'"
|
||||||
@@ -500,6 +501,23 @@ CERT_PUB_KEY=$(python manage.py get_config certfile)
|
|||||||
CERT_PRIV_KEY=$(python manage.py get_config keyfile)
|
CERT_PRIV_KEY=$(python manage.py get_config keyfile)
|
||||||
deactivate
|
deactivate
|
||||||
|
|
||||||
|
HAS_ALLAUTH=$(grep HEADLESS_FRONTEND_URLS $local_settings)
|
||||||
|
if ! [[ $HAS_ALLAUTH ]]; then
|
||||||
|
source /rmm/api/env/bin/activate
|
||||||
|
cd /rmm/api/tacticalrmm
|
||||||
|
ROOT_DOMAIN=$(python manage.py get_config rootdomain)
|
||||||
|
deactivate
|
||||||
|
allauth="$(
|
||||||
|
cat <<EOF
|
||||||
|
SESSION_COOKIE_DOMAIN = '${ROOT_DOMAIN}'
|
||||||
|
CSRF_COOKIE_DOMAIN = '${ROOT_DOMAIN}'
|
||||||
|
CSRF_TRUSTED_ORIGINS = ["https://${FRONTEND}", "https://${API}"]
|
||||||
|
HEADLESS_FRONTEND_URLS = {"socialaccount_login_error": "https://${FRONTEND}/account/provider/callback"}
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
echo "${allauth}" | tee --append $local_settings >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
print_green 'Restoring hosts file'
|
print_green 'Restoring hosts file'
|
||||||
|
|
||||||
if grep -q manage_etc_hosts /etc/hosts; then
|
if grep -q manage_etc_hosts /etc/hosts; then
|
||||||
|
19
update.sh
19
update.sh
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
SCRIPT_VERSION="154"
|
SCRIPT_VERSION="155"
|
||||||
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/update.sh'
|
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/update.sh'
|
||||||
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
|
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
@@ -452,6 +452,23 @@ CERT_PUB_KEY=$(python manage.py get_config certfile)
|
|||||||
CERT_PRIV_KEY=$(python manage.py get_config keyfile)
|
CERT_PRIV_KEY=$(python manage.py get_config keyfile)
|
||||||
deactivate
|
deactivate
|
||||||
|
|
||||||
|
HAS_ALLAUTH=$(grep HEADLESS_FRONTEND_URLS $local_settings)
|
||||||
|
if ! [[ $HAS_ALLAUTH ]]; then
|
||||||
|
source /rmm/api/env/bin/activate
|
||||||
|
cd /rmm/api/tacticalrmm
|
||||||
|
ROOT_DOMAIN=$(python manage.py get_config rootdomain)
|
||||||
|
deactivate
|
||||||
|
allauth="$(
|
||||||
|
cat <<EOF
|
||||||
|
SESSION_COOKIE_DOMAIN = '${ROOT_DOMAIN}'
|
||||||
|
CSRF_COOKIE_DOMAIN = '${ROOT_DOMAIN}'
|
||||||
|
CSRF_TRUSTED_ORIGINS = ["https://${FRONTEND}", "https://${API}"]
|
||||||
|
HEADLESS_FRONTEND_URLS = {"socialaccount_login_error": "https://${FRONTEND}/account/provider/callback"}
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
echo "${allauth}" | tee --append $local_settings >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
if grep -q manage_etc_hosts /etc/hosts; then
|
if grep -q manage_etc_hosts /etc/hosts; then
|
||||||
sudo sed -i '/manage_etc_hosts: true/d' /etc/cloud/cloud.cfg >/dev/null
|
sudo sed -i '/manage_etc_hosts: true/d' /etc/cloud/cloud.cfg >/dev/null
|
||||||
if ! grep -q "manage_etc_hosts: false" /etc/cloud/cloud.cfg; then
|
if ! grep -q "manage_etc_hosts: false" /etc/cloud/cloud.cfg; then
|
||||||
|
Reference in New Issue
Block a user