Skip to content

Commit

Permalink
Merge pull request #8173 from OpenMined/yash/hosts-patch
Browse files Browse the repository at this point in the history
Automatically apply fixes to hosts file
  • Loading branch information
yashgorana authored Oct 26, 2023
2 parents 5625eb0 + ff7c4ed commit df1a184
Show file tree
Hide file tree
Showing 3 changed files with 275 additions and 31 deletions.
15 changes: 7 additions & 8 deletions packages/grid/devspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,16 +325,15 @@ profiles:
path: deployments.seaweedfs-config

commands:
start:
command: |-
tox -e dev.k8s.start
deploy:
command: |-
devspace use context k3d-syft-dev
devspace use namespace syft
devspace deploy --var CONTAINER_REGISTRY=k3d-registry.localhost:12345
devspace deploy --kube-context k3d-syft-dev --namespace syft --var CONTAINER_REGISTRY=k3d-registry.localhost:12345
dev:
command: |-
devspace use context k3d-syft-dev
devspace use namespace syft
devspace dev --var CONTAINER_REGISTRY=k3d-registry.localhost:12345
contexts:
devspace dev --kube-context k3d-syft-dev --namespace syft --var CONTAINER_REGISTRY=k3d-registry.localhost:12345
info:
command: |-
kubectl config get-contexts
tox -e dev.k8s.info
212 changes: 212 additions & 0 deletions scripts/patch_hosts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# stdlib
import argparse
from functools import cached_property
import os
from pathlib import Path
import platform
import re
import sys


class Platform:
system = platform.system()
uname = platform.uname()

@staticmethod
def get() -> str:
return Platform.system

@staticmethod
def windows() -> bool:
return Platform.system == "Windows"

@staticmethod
def macos() -> bool:
return Platform.system == "Darwin"

@staticmethod
def linux() -> bool:
return Platform.system == "Linux"

@staticmethod
def wsl2() -> bool:
return "wsl2" in Platform.uname.release.lower()


class Hosts:
def __init__(self, path: str = None) -> None:
self.__path = path
self.content = self.read()

@cached_property
def path(self) -> Path:
if self.__path:
p = self.__path
elif Platform.linux():
p = "/etc/hosts"
elif Platform.macos():
new_hosts = "/etc/hosts"
old_hosts = "/private/etc/hosts"
p = new_hosts if os.path.exists(new_hosts) else old_hosts
elif Platform.windows():
p = "C:\Windows\System32\drivers\etc\hosts"
else:
raise Exception(f"Unsupported OS: {Platform.system}")

p = Path(p).absolute()
assert p.exists(), "Host file does not exist"
return p

def read(self) -> str:
return self.path.read_text()

def get(self, domain: str) -> list[str]:
return re.findall(f"(.+)\s+{domain}", self.content)

def add(self, ip: str, domain: str) -> None:
if self.get(domain):
return

self.content = self.content.rstrip() + f"\n{ip}\t{domain}"
self.__write()

def remove(self, domain: str) -> None:
if not self.get(domain):
return

self.content = re.sub(f"(.+)\s+{domain}\n", "", self.content)
self.__write()

def update(self, ip: str, domain: str) -> None:
if not self.get(domain):
self.add(ip, domain)

# inplace
self.content = re.sub(f"(.+)\s+{domain}\n", f"{ip}\t{domain}\n", self.content)
self.__write()

def __write(self) -> None:
cleaned = re.sub("\n{2}\n+", "\n", self.content)
self.path.write_text(cleaned.rstrip() + "\n")


def running_as_root() -> bool:
if not Platform.windows():
return os.geteuid() == 0
else:
# stdlib
import ctypes

return ctypes.windll.shell32.IsUserAnAdmin() == 1


def wsl2_disable_auto_hosts() -> None:
if not Platform.wsl2():
return

# stdlib
import configparser

conf_path = Path("/etc/wsl.conf")
conf = configparser.ConfigParser()
conf.optionxform = str
conf.read(conf_path)

if "network" not in conf:
conf["network"] = {}

if conf["network"]["generateHosts"] != "false":
conf["network"]["generateHosts"] = "false"
with conf_path.open("w") as fp:
conf.write(fp)


def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--add",
nargs=2,
action="append",
default=[],
metavar=("IP", "DOMAIN"),
help="Add entry to hosts file",
)
parser.add_argument(
"--add-k3d-registry",
action="store_true",
default=False,
help="Add entry for k3d-registry.localhost",
)
parser.add_argument(
"--fix-docker-hosts",
action="store_true",
default=False,
help="Windows - Fix *.docker.internal. Linux/macOS - remove them",
)
parser.add_argument(
"--disable-wsl2-auto-hosts",
action="store_true",
default=False,
dest="wsl2_disable_auto_hosts",
help="[Optional] Disable automatic /etc/hosts generation from Windows in WSL2",
)
parser.add_argument(
"--hosts",
type=Path,
default=None,
help="[Optional] Path to a hosts-like file",
)

if len(sys.argv) < 2:
parser.print_help()
sys.exit(1)

args = parser.parse_args()

if not args.hosts and not running_as_root():
print(
"ERROR: This script must be run as root since it will modify system hosts file"
)
sys.exit(1)

hosts = Hosts(args.hosts)

print(">> Args", args.__dict__)
print(">> OS:", Platform.system)
print(">> Release:", Platform.uname.release)
print(">> Version:", Platform.uname.version)
print(">> Hosts file:", hosts.path)

if len(args.add):
for ip, domain in args.add:
print(f">> Adding {ip} {domain}")
hosts.update(ip, domain)

if args.add_k3d_registry:
print(">> Adding k3d registry host entry")
hosts.update("127.0.0.1", "k3d-registry.localhost")

if args.fix_docker_hosts:
if Platform.windows() or Platform.wsl2():
print(">> Fixing docker host entries for Windows/WSL2")
hosts.update("0.0.0.0", "host.docker.internal")
hosts.update("0.0.0.0", "gateway.docker.internal")
hosts.update("127.0.0.1", "kubernetes.docker.internal")
else:
print(">> Removing docker host entries")
hosts.remove("host.docker.internal")
hosts.remove("gateway.docker.internal")
hosts.remove("kubernetes.docker.internal")

if args.wsl2_disable_auto_hosts and Platform.wsl2():
print(">> Disabling auto hosts generation")
wsl2_disable_auto_hosts()

print(">> Done")
print("-" * 50)
print(hosts.read())
print("-" * 50)


if __name__ == "__main__":
main()
79 changes: 56 additions & 23 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
[tox]
envlist =
dev.k8s.registry
dev.k8s.start
dev.k8s.deploy
dev.k8s.info
dev.k8s.destroy
dev.k8s.destroyall
hagrid.publish
lint
stack.test.integration
Expand Down Expand Up @@ -936,52 +942,79 @@ commands =
pytest

[testenv:dev.k8s.registry]
changedir = {toxinidir}/packages/grid
description = Start local Kubernetes registry with k3d
changedir = {toxinidir}
passenv=HOME,USER
allowlist_externals =
bash
sudo
commands =
bash -c 'k3d registry create registry.localhost --port 12345 -v $HOME/.k3d-registry:/var/lib/registry'
bash -c '\
CYAN="\033[1;36m"; \
CLEAR="\033[0m"; \
printf "\n${CYAN}---------------------------------------------------------\n" ;\
printf "Make sure to add the following to your /etc/hosts file:${CLEAR}\n";\
printf "127.0.0.1 k3d-registry.localhost\n";\
printf "${CYAN}---------------------------------------------------------${CLEAR}\n"'
bash -c 'k3d registry create registry.localhost --port 12345 -v $HOME/.k3d-registry:/var/lib/registry || true'
sudo {envpython} scripts/patch_hosts.py --add-k3d-registry --fix-docker-hosts

[testenv:dev.k8s.start]
changedir = {toxinidir}/packages/grid
description = Start local Kubernetes registry & cluster with k3d
changedir = {toxinidir}
passenv=*
allowlist_externals =
bash
k3d
sleep
tox
commands =
bash -c 'URL=http://k3d-registry.localhost:12345/v2/_catalog; \
curl -X GET $URL || (echo "ERROR: Add \"127.0.0.1 k3d-registry.localhost\" to /etc/hosts" && exit 1)'
tox -e dev.k8s.registry
sleep 3
bash -c 'URL=http://k3d-registry.localhost:12345/v2/_catalog; curl -X GET $URL'
bash -c 'k3d cluster create syft-dev -p "8080:80@loadbalancer" --registry-use k3d-registry.localhost:12345; \
k3d cluster list'
kubectl create namespace syft;'
tox -e dev.k8s.info

[testenv:dev.k8s.deploy]
description = Deploy to a local Kubernetes cluster with Devspace
changedir = {toxinidir}/packages/grid
passenv=HOME, USER
allowlist_externals =
bash
commands =
bash -c '\
devspace use context k3d-syft-dev; \
devspace use namespace syft; \
devspace deploy --var CONTAINER_REGISTRY=k3d-registry.localhost:12345 --config=devspace.yaml'
bash -c 'devspace deploy -b --kube-context k3d-syft-dev --namespace syft --var CONTAINER_REGISTRY=k3d-registry.localhost:12345'

[testenv:dev.k8s.info]
description = Gather info about the localKubernetes cluster
passenv=HOME, USER
ignore_errors = True
allowlist_externals =
k3d
kubectl
commands =
kubectl config view
k3d cluster list
kubectl cluster-info
kubectl config current-context
kubectl get namespaces

[testenv:dev.k8s.cleanup]
[testenv:dev.k8s.destroy]
description = Destroy local Kubernetes cluster
changedir = {toxinidir}/packages/grid
passenv=HOME, USER
allowlist_externals =
bash
commands =
bash -c '\
devspace use context k3d-syft-dev; \
devspace use namespace syft; \
devspace purge; \
devspace purge --kube-context k3d-syft-dev --namespace syft; \
rm -rf .devspace; echo ""; \
k3d cluster delete syft-dev; echo ""; \
k3d registry delete registry.localhost; echo "";\
kubectl config view'

[testenv:dev.k8s.destroyall]
description = Destroy both local Kubernetes cluster and registry
changedir = {toxinidir}
passenv=HOME, USER
ignore_errors=True
allowlist_externals =
bash
tox
sudo
rm
commands =
tox -e dev.k8s.destroy
bash -c 'k3d registry delete registry.localhost || true'
sudo rm -rf ~/.k3d-registry

0 comments on commit df1a184

Please sign in to comment.