Skip to content
Snippets Groups Projects
Select Git revision
  • 176fb6565ed4ff6d21d1db755bea2866bfc98fe3
  • master default protected
  • deploy-components-parallel
  • fix-chrony-exporter
  • L2SS-2407-swap-iers-caltable-monitoring-port
  • L2SS-2357-fix-ruff
  • sync-up-with-meta-pypcc
  • stabilise-landing-page
  • all-stations-lofar2
  • v0.39.7-backports
  • Move-sdptr-to-v1.5.0
  • fix-build-ubuntu
  • tokens-in-env-files
  • fix-build
  • L2SS-2214-deploy-cdb
  • fix-missing-init
  • add-power-hardware-apply
  • L2SS-2129-Add-Subrack-Routine
  • Also-listen-internal-to-rpc
  • fix-build-dind
  • L2SS-2153--Improve-Error-Handling
  • v0.52.8-rc1 protected
  • v0.55.5 protected
  • v0.55.4 protected
  • 0.55.2.dev0
  • 0.55.1.dev0
  • 0.55.0.dev0
  • v0.54.0 protected
  • 0.53.2.dev0
  • 0.53.1.dev0
  • v0.52.3-r2 protected
  • remove-snmp-client
  • v0.52.3 protected
  • v0.52.3dev0 protected
  • 0.53.1dev0
  • v0.52.2-rc3 protected
  • v0.52.2-rc2 protected
  • v0.52.2-rc1 protected
  • v0.52.1.1 protected
  • v0.52.1 protected
  • v0.52.1-rc1 protected
41 results

Makefile

Blame
  • lukken's avatar
    L2SS-988: Prevent waiting on services without health property
    Corné Lukken authored
    176fb656
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Makefile 10.46 KiB
    # Set dir of Makefile to a variable to use later
    MAKEPATH := $(abspath $(lastword $(MAKEFILE_LIST)))
    BASEDIR := $(notdir $(patsubst %/,%,$(dir $(MAKEPATH))))
    
    DOCKER_COMPOSE_ENV_FILE := $(abspath .env)
    COMPOSE_FILES := $(wildcard *.yml)
    COMPOSE_FILE_ARGS := --env-file $(DOCKER_COMPOSE_ENV_FILE) $(foreach yml,$(COMPOSE_FILES),-f $(yml))
    
    ATTACH_COMPOSE_FILE_ARGS := $(foreach yml,$(filter-out tango.yml,$(COMPOSE_FILES)),-f $(yml))
    
    # The default Docker network mode is tangonet.  The "host" network
    # mode will make the tangodb and archiverdb ports clash,
    # But we allow to overwrite it.
    NETWORK_MODE ?= tangonet
    
    # Timeout used to await services to become healthy
    TIMEOUT ?= 300
    
    SCRATCH ?= /tmp
    
    # Host name through which others can reach our control interfaces.
    # Needs to be resolvable from the containers and clients.
    ifneq (,$(wildcard /run/WSL))
        # Microsoft Windows Subsystem for Linux
        HOSTNAME ?= host.docker.internal
    else
        HOSTNAME ?= $(shell hostname -f)
    endif
    
    # Host name to which to send our container logs. Needs to be resolvable from
    # the host.
    LOG_HOSTNAME ?= localhost
    
    # If the first make argument is "start", "stop"...
    ifeq (start,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (stop,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (restart,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (up,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (build,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (build-nocache,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (attach,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
        ifndef NETWORK_MODE
            $(error NETWORK_MODE must specify the network to attach to, e.g., make NETWORK_MODE=tangonet-powersupply ...)
        endif
    
        ifndef TANGO_HOST
            $(error TANGO_HOST must specify the Tango database device, e.g., make TANGO_HOST=powersupply-databaseds:10000 ...)
        endif
    else ifeq (await,$(firstword $(MAKECMDGOALS)))
        SERVICE_TARGET = true
    else ifeq (run,$(firstword $(MAKECMDGOALS)))
        RUN_TARGET = true
    else ifeq (integration,$(firstword $(MAKECMDGOALS)))
        INTEGRATION_TARGET = true
    endif
    
    ifdef SERVICE_TARGET
        # .. then use the rest as arguments for the make target
        SERVICE := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
        # ...and turn them into do-nothing targets
        $(eval $(SERVICE):;@:)
    else ifdef RUN_TARGET
        # Isolate second argument as service, the rest is arguments for run command
        SERVICE := $(wordlist 2, 2, $(MAKECMDGOALS))
        # ...and turn them into do-nothing targets
        $(eval $(SERVICE):;@:)
        SERVICE_ARGS := $(wordlist 3, $(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
        $(eval $(SERVICE_ARGS):;@:)
    else ifdef INTEGRATION_TARGET
        # Isolate second argument as integration module, the rest as arguments
        INTEGRATION_MODULE := $(wordlist 2, 2, $(MAKECMDGOALS))
         $(eval $(INTEGRATION_MODULE):;@:)
        INTEGRATION_ARGS := $(wordlist 3, $(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
        $(eval $(INTEGRATION_ARGS):;@:)
    endif
    
    #
    # Never use the network=host mode when running CI jobs, and add extra
    # distinguishing identifiers to the network name and container names to
    # prevent collisions with jobs from the same project running at the same
    # time.
    #
    ifneq ($(CI_JOB_ID),)
        NETWORK_MODE := tangonet-$(CI_JOB_ID)
        CONTAINER_NAME_PREFIX := $(CI_JOB_ID)-
    else
        CONTAINER_NAME_PREFIX :=
        $(info Network mode cannot be host for the archiver! It won't work unless you set the env var CI_JOB_ID=local)
    endif
    
    ifeq ($(OS),Windows_NT)
        $(error Sorry, Windows is not supported yet)
    else
        UNAME_S := $(shell uname -s)
    
        ifeq ($(UNAME_S),Linux)
            DOCKER_GID ?= $(shell getent group docker | cut -d: -f 3)
            DISPLAY ?= :0.0
            XAUTHORITY_MOUNT := /tmp/.X11-unix:/tmp/.X11-unix
            XAUTHORITY ?= /hosthome/.Xauthority
            # /bin/sh (=dash) does not evaluate 'docker network' conditionals correctly
            SHELL := /bin/bash
        else ifeq ($(UNAME_S),Darwin)
            DOCKER_GID ?= $(shell id -g)
            IF_INTERFACE := $(shell scutil --nwi | grep 'Network interfaces:' | cut -d' ' -f3)
            IP_ADDRESS := $(shell scutil --nwi | grep 'address' | cut -d':' -f2 | tr -d ' ' | head -n1)
            DISPLAY := $(IP_ADDRESS):0
            # Make sure that Darwin, especially from macOS Catalina on,
            # allows X access from our Docker containers.
            ADD_TO_XHOST := $(shell xhost +$(IP_ADDRESS))
            XAUTHORITY_MOUNT := $(HOME)/.Xauthority:/hosthome/.Xauthority:ro
            XAUTHORITY := /hosthome/.Xauthority
        endif
    endif
    
    #
    # When uunning in network=host mode, point devices at a port on the host
    # machine rather than at the container.
    #
    ifeq ($(NETWORK_MODE),host)
        TANGO_HOST := $(shell hostname):10000
        MYSQL_HOST := $(shell hostname):3306
    else
        ifeq ($(TANGO_HOST),)
            # Use FQDN for TANGO_HOST to avoid confusion in the archiver, which also
            # adds the domain.
            TANGO_HOST := $(CONTAINER_NAME_PREFIX)databaseds.$(NETWORK_MODE):10000
        else
            TANGO_HOST := $(TANGO_HOST)
        endif
    
        ifeq ($(MYSQL_HOST),)
            MYSQL_HOST := $(CONTAINER_NAME_PREFIX)tangodb:3306
        else
            MYSQL_HOST := $(MYSQL_HOST)
        endif
    endif
    
    DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) \
        XAUTHORITY=$(XAUTHORITY) \
        TANGO_HOST=$(TANGO_HOST) \
        MYSQL_HOST=$(MYSQL_HOST) \
        HOSTNAME=$(HOSTNAME) \
        SCRATCH=$(SCRATCH) \
        LOG_HOSTNAME=$(LOG_HOSTNAME) \
        NETWORK_MODE=$(NETWORK_MODE) \
        XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) \
        CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) \
        COMPOSE_IGNORE_ORPHANS=true \
        CONTAINER_EXECUTION_UID=$(shell id -u) \
        DOCKER_GID=$(DOCKER_GID) \
        TEST_MODULE=$(INTEGRATION_MODULE)
    
    
    .PHONY: up down minimal context run integration start stop restart build build-nocache status clean pull help
    .DEFAULT_GOAL := help
    
    pull: ## pull the images from the Docker hub
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) pull
    
    build: context ## rebuild images
    	# docker-compose does not support build dependencies, so manage those here
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --parallel --progress=plain $(SERVICE)
    
    build-nocache: context ## rebuild images from scratch
    	# docker-compose does not support build dependencies, so manage those here
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --no-cache --progress=plain $(SERVICE)
    
    up: minimal  ## start the base TANGO system and prepare requested services
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up --no-start --no-recreate $(SERVICE)
    
    run: minimal  ## run a service using arguments and delete it afterwards
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) run -T --no-deps --rm $(SERVICE) $(SERVICE_ARGS)
    
    integration: minimal  ## run a service using arguments and delete it afterwards
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) run -T --no-deps --rm integration-test $(INTEGRATION_ARGS)
    
    down:  ## stop all services and tear down the system
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down
    ifneq ($(NETWORK_MODE),host)
    	docker network inspect $(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm $(NETWORK_MODE)) || true
    	docker network inspect 9000-$(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm 9000-$(NETWORK_MODE)) || true
    endif
    
    minimal: context ## start the base TANGO system
    ifneq ($(NETWORK_MODE),host)
    	docker network inspect $(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create $(NETWORK_MODE))
    	docker network inspect 9000-$(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create 9000-$(NETWORK_MODE) -o com.docker.network.driver.mtu=9000)
    endif
    
    	$(DOCKER_COMPOSE_ARGS) docker-compose -f tango.yml -f networks.yml up --no-recreate -d
    
    context: ## Move the necessary files to create minimal docker context
    	@mkdir -p tmp
    	@cp ../tangostationcontrol/requirements.txt tmp/
    
    bootstrap: pull build # first start, initialise from scratch
    	$(MAKE) start elk-configure-host # configure host kernel for elk container
    	$(MAKE) start dsconfig # boot up containers to load configurations
    	sleep 5 # wait for dsconfig container to come up
    	../sbin/update_ConfigDb.sh ../CDB/LOFAR_ConfigDb.json # load default configuration
    	../sbin/update_ConfigDb.sh ../CDB/tango-archiver-data/archiver-devices.json # load default archive configuration
    	../sbin/update_ConfigDb.sh ../CDB/stations/simulators_ConfigDb.json # by default, use simulators
    
    start: up ## start a service (usage: make start <servicename>)
    	if [ $(UNAME_S) = Linux ]; then touch ~/.Xauthority; chmod a+r ~/.Xauthority; fi
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) start $(SERVICE)
    
    stop:  ## stop a service (usage: make stop <servicename>)
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) stop $(SERVICE)
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) rm -f $(SERVICE)
    
    restart: ## restart a service (usage: make restart <servicename>)
    	make stop $(SERVICE) # cannot use dependencies, as that would allow start and stop to run in parallel..
    	make start $(SERVICE)
    
    attach:  ## attach a service to an existing Tango network
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(ATTACH_COMPOSE_FILE_ARGS) up --no-recreate -d $(SERVICE)
    
    time := 0
    await:  ## Await every container with total max timeout of 300, do not reset timeout
    	for i in $(SERVICE); do \
    		current_service=$$($(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) ps -q $${i}); \
    		if [ -z "$${current_service}" ]; then \
    		    continue; \
            fi; \
            service_has_health=$$(docker inspect -f '{{.State.Health.Status}}' $${current_service}); \
            if [ -z "$${service_has_health}" ]; then \
                continue; \
            fi; \
    		while [ "$$(docker inspect -f '{{.State.Health.Status}}' $${current_service})" != "healthy" ] ; do \
    			sleep 1; \
    			time=$$(expr $$time + 1); \
    			if [ $${time} -gt $(TIMEOUT) ]; then \
    				echo "Timeout reached waiting for $${i} to become healthy"; \
    				exit 1; \
    			fi; \
    		done; \
    		echo "Service $${i} is healthy"; \
    	done
    
    status:  ## show the container status
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) ps
    
    images:  ## show the container images
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) images
    
    clean: down  ## clear all TANGO database entries, and all containers
    	docker volume rm $(BASEDIR)_tangodb
    	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) rm -f
    
    help:   ## show this help.
    	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'