diff --git a/.ansible-lint b/.ansible-lint index a6d8f52..5cbfa93 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -1,3 +1,6 @@ --- skip_list: - - role-name + - fqcn[action-core] # Use FQCN for builtin module actions + - fqcn[action] # Use FQCN for module actions, such `..docker_container`. (warning) + - name[casing] # All names should start with an uppercase letter. (warning) + - name[template] # Jinja templates should only be at the end of 'name' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3c2eae6..02988f4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,65 +1,51 @@ --- name: CI -'on': - pull_request: - push: - branches: - - main + +on: schedule: - - cron: "0 2 * * 0" + - cron: "0 4 * * 0" + workflow_dispatch: + workflow_run: + workflows: + - "code linter" + # branches: + # - main + # - feature/** + # - fix/** + types: + - completed defaults: run: working-directory: 'ansible-urbanterror' jobs: - lint: - name: linting - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: lint - uses: docker://ghcr.io/github/super-linter:slim-v4 - env: - # DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GH_REGISTRY_TOKEN }} - VALIDATE_ALL_CODEBASE: true - VALIDATE_ANSIBLE: true - # VALIDATE_MARKDOWN: trues - VALIDATE_YAML: true - - test: - name: "${{ matrix.image }} / python: ${{ matrix.python-version }}, ansible: ${{ matrix.ansible-version }}" - needs: - - lint - runs-on: ubuntu-18.04 + deb: + name: "${{ matrix.image }} / ansible: ${{ matrix.ansible-version }}" + runs-on: ubuntu-20.04 + if: ${{ github.event_name == 'schedule' || github.event.workflow_run.conclusion == 'success' }} strategy: fail-fast: false matrix: image: - - debian:10 - debian:11 - ubuntu:20.04 - python-version: - - '3.9' ansible-version: - - '4.1.0' - - '5.1.0' + - '5.1' + - '6.1' + scenario: + - default steps: - name: check out the codebase. - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: 'ansible-urbanterror' - - name: set up python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + - name: 🐍 set up python + uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} + python-version: '3.x' - name: install dependencies run: | @@ -68,21 +54,9 @@ jobs: - name: test with tox run: | - tox -e py$(printf "${{ matrix.python-version }}" | tr -d '.')-ansible$(printf "${{ matrix.ansible-version }}" | tr -d '.') \ - -- molecule test + tox -e ansible_$(printf "${{ matrix.ansible-version }}") \ + -- molecule test --scenario-name default env: PY_COLORS: '1' ANSIBLE_FORCE_COLOR: '1' DISTRIBUTION: ${{ matrix.image }} - - publish: - if: github.ref == 'refs/heads/main' - needs: - - test - runs-on: ubuntu-18.04 - steps: - - name: galaxy - uses: robertdebock/galaxy-action@1.2.0 - with: - galaxy_api_key: ${{ secrets.galaxy_api_key }} - git_branch: main diff --git a/.gitignore b/.gitignore index bf1c353..f628c27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .tox -__pycache__ .galaxy_install_info +*kate-swp +__pycache__ + .cache diff --git a/.yamllint b/.yamllint index c98674b..e9487f6 100644 --- a/.yamllint +++ b/.yamllint @@ -4,20 +4,21 @@ rules: line-length: max: 195 level: warning - braces: - min-spaces-inside: 0 - max-spaces-inside: 1 - brackets: - min-spaces-inside: 0 - max-spaces-inside: 1 - indentation: - spaces: 2 - comments: disable - comments-indentation: disable - truthy: disable +# braces: +# min-spaces-inside: 0 +# max-spaces-inside: 1 +# brackets: +# min-spaces-inside: 0 +# max-spaces-inside: 1 +# indentation: +# spaces: 2 +# comments: disable +# comments-indentation: disable ignore: | - tests/ - molecule/ - .tox .github + .molecule/ + .tox + .travis.yml + molecule/ + tests/ diff --git a/Makefile b/Makefile index 6c4b2c2..40857c8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # export TOX_SCENARIO ?= default -export TOX_PYTHON ?= py310 -export TOX_ANSIBLE ?= ansible510 +# export TOX_PYTHON ?= py310 +export TOX_ANSIBLE ?= ansible_6.1 .PHONY: converge destroy verify lint diff --git a/defaults/main.yml b/defaults/main.yml index b6f94ad..c31a0db 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -2,6 +2,8 @@ urbanterror_admin_password: s3cr3T-are-p0ssiBL3 +urbanterror_version: 4.3.4 + urbanterror_start_map: ut4_riyadh urbanterror_game_type: CaptureTheFlag @@ -13,7 +15,7 @@ urbanterror_binary: "Quake3-UrT-Ded.{{ ansible_machine }}" urbanterror_config: # intition version: 4.0.3 - current_version: '4.0.3' + current_version: "{{ urbanterror_version }}" # id: 2 = download_server: '2' # id: 1 = Quake3-UrT (default) diff --git a/files/updater.sh b/files/updater.sh index 52e4cb7..c3543f6 100644 --- a/files/updater.sh +++ b/files/updater.sh @@ -258,7 +258,7 @@ function doBrowser () $BROWSER "$TMPFILE" fi - rm -f "$TMPFILE" + # rm -f "$TMPFILE" } function drawLicence () diff --git a/hooks/converge b/hooks/converge index 7e23550..5df5ad6 100755 --- a/hooks/converge +++ b/hooks/converge @@ -1,10 +1,5 @@ #!/usr/bin/env bash -TOX_ARGS= +. hooks/_tox_base -if [ -n "${TOX_SCENARIO}" ] -then - TOX_ARGS="--scenario-name ${TOX_SCENARIO}" -fi - -tox -e ${TOX_PYTHON}-${TOX_ANSIBLE} -- molecule converge ${TOX_ARGS} +tox ${TOX_OPTS} -- molecule converge ${TOX_ARGS} diff --git a/hooks/destroy b/hooks/destroy index d7cda5f..98fcf16 100755 --- a/hooks/destroy +++ b/hooks/destroy @@ -1,10 +1,5 @@ #!/usr/bin/env bash -TOX_ARGS= +. hooks/_tox_base -if [ -n "${TOX_SCENARIO}" ] -then - TOX_ARGS="--scenario-name ${TOX_SCENARIO}" -fi - -tox -e ${TOX_PYTHON}-${TOX_ANSIBLE} -- molecule destroy ${TOX_ARGS} +tox ${TOX_OPTS} -- molecule destroy ${TOX_ARGS} diff --git a/hooks/lint b/hooks/lint index 7fac485..6cf7ff3 100755 --- a/hooks/lint +++ b/hooks/lint @@ -1,10 +1,5 @@ #!/usr/bin/env bash -TOX_ARGS= +. hooks/_tox_base -if [ -n "${TOX_SCENARIO}" ] -then - TOX_ARGS="--scenario-name ${TOX_SCENARIO}" -fi - -tox -e ${TOX_PYTHON}-${TOX_ANSIBLE} -- molecule lint ${TOX_ARGS} +tox ${TOX_OPTS} -- molecule lint ${TOX_ARGS} diff --git a/hooks/verify b/hooks/verify index 540f8d3..79a38d4 100755 --- a/hooks/verify +++ b/hooks/verify @@ -1,10 +1,5 @@ #!/usr/bin/env bash -TOX_ARGS= +. hooks/_tox_base -if [ -n "${TOX_SCENARIO}" ] -then - TOX_ARGS="--scenario-name ${TOX_SCENARIO}" -fi - -tox -e ${TOX_PYTHON}-${TOX_ANSIBLE} -- molecule verify ${TOX_ARGS} +tox ${TOX_OPTS} -- molecule verify ${TOX_ARGS} diff --git a/library/urbanterror_api.py b/library/urbanterror_api.py index 7b2fb0e..b206b04 100644 --- a/library/urbanterror_api.py +++ b/library/urbanterror_api.py @@ -68,12 +68,12 @@ def run(self): """ """ - return_code, data = self.__api_data() + return_code, data = self.download_manifest() - if(return_code == 200): + if return_code == 200: """ """ - if(self.get == 'api_version'): + if self.get == 'api_version': result = self.__parse_api_version(data) return dict( @@ -81,7 +81,7 @@ def run(self): api_version=result ) - if(self.get == 'version'): + if self.get == 'version': result = self.__parse_version(data) return dict( @@ -89,7 +89,7 @@ def run(self): versions=result ) - if(self.get == 'server_list'): + if self.get == 'server_list': result = self.__parse_server_list(data) return dict( @@ -97,7 +97,7 @@ def run(self): server_list=result ) - if(self.get == 'engine_list'): + if self.get == 'engine_list': result = self.__parse_engine_list(data) return dict( @@ -105,11 +105,9 @@ def run(self): engine_list=result ) - self.module.log("--------------------------------------") - self.module.log( - msg="result {} ({})".format(result, type(result)) - ) - self.module.log("--------------------------------------") + # self.module.log("--------------------------------------") + # self.module.log(msg=f"result {result} ({type(result)})") + # self.module.log("--------------------------------------") return dict( failed = True @@ -129,7 +127,7 @@ def __parse_api_version(self, data): except Exception as e: self.module.log( - msg=" text: {} ({})".format(e, type(e)) + msg=f" text: {e} ({type(e)})" ) pass @@ -142,9 +140,7 @@ def __parse_version(self, data): version_list = data.get('VersionList') - self.module.log( - msg=" - {} ({})".format(version_list, type(version_list)) - ) + self.module.log(msg=f" - {version_list} ({type(version_list)})") try: versions = json.loads( @@ -154,7 +150,7 @@ def __parse_version(self, data): for i in versions.get('Version'): i['id'] = i.get('VersionNumber') i['version'] = i.get('VersionName').split(' ')[0] - if(len(i.get('VersionName').split(' ')) == 2): + if (len(i.get('VersionName').split(' ')) == 2): i['latest'] = True else: i['latest'] = False @@ -165,9 +161,7 @@ def __parse_version(self, data): release_date=i.get('ReleaseDate') ) except Exception as e: - self.module.log( - msg=" text: {} ({})".format(e, type(e)) - ) + self.module.log(msg=f" text: {e} ({type(e)})") pass return result @@ -191,9 +185,7 @@ def __parse_server_list(self, data): ) except Exception as e: - self.module.log( - msg=" text: {} ({})".format(e, type(e)) - ) + self.module.log(msg=f" text: {e} ({type(e)})") pass return result @@ -212,7 +204,7 @@ def __parse_engine_list(self, data): _engine_name = i.get('EngineName').split(' ') _default_engine = False - if('default' in _engine_name[1].lower()): + if ('default' in _engine_name[1].lower()): _default_engine = True i['name'] = _engine_name[0].lower() @@ -226,17 +218,16 @@ def __parse_engine_list(self, data): ) except Exception as e: - self.module.log( - msg=" text: {} ({})".format(e, type(e)) - ) + self.module.log(msg=f" text: {e} ({type(e)})") pass return result - def __api_data(self): + def download_manifest(self): """ """ updater_data = dict() + output_dict = dict() payload = { 'platform': self.platform, @@ -247,37 +238,34 @@ def __api_data(self): 'server': self.server, 'updaterVersion': self.updaterVersion } + # self.module.log(msg=f" payload: {payload}") - self.module.log(msg=" payload: {}".format(payload)) + code, ret = self.__call_url(data=payload) - code, ret = self.__call_url( - data=payload - ) - - if(code == 200 and len(ret) != 0): + if code == 200 and len(ret) != 0: import xmltodict - # obj = untangle.parse(XML) - obj = xmltodict.parse( - ret - ) - + obj = xmltodict.parse(ret) updater_data = obj['Updater'] + # convert an OrderedDict to an regular dict + output_dict = json.loads(json.dumps(updater_data)) - return code, updater_data + # self.module.log(msg=f"{type(output_dict)}") + # self.module.log(msg=f"{json.dumps(output_dict, indent=2, sort_keys=True)}") + + return code, output_dict def __call_url(self, method='POST', data=None): """ """ - headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' } - self.module.log(msg=" data : {}".format(data)) - self.module.log(msg=" headers: {}".format(headers)) + # self.module.log(msg=" data : {}".format(data)) + # self.module.log(msg=" headers: {}".format(headers)) try: - if(method == 'POST'): + if method == 'POST': ret = requests.post( self.url, data=data, @@ -290,11 +278,11 @@ def __call_url(self, method='POST', data=None): ret.raise_for_status() - self.module.log(msg="------------------------------------------------------------------") - # self.module.log(msg=" text : {}".format(ret.text)) - self.module.log(msg=" headers : {}".format(ret.headers)) - self.module.log(msg=" code : {}".format(ret.status_code)) - self.module.log(msg="------------------------------------------------------------------") + # self.module.log(msg="------------------------------------------------------------------") + # # self.module.log(msg=" text : {}".format(ret.text)) + # self.module.log(msg=" headers : {}".format(ret.headers)) + # self.module.log(msg=" code : {}".format(ret.status_code)) + # self.module.log(msg="------------------------------------------------------------------") return ret.status_code, ret.text @@ -312,14 +300,32 @@ def main(): """ module = AnsibleModule( argument_spec=dict( - url=dict(required=True), - get=dict(required=True), - engine=dict(required=False), - server=dict(required=False), - updaterVersion=dict(required=False), - version=dict(required=False), - platform=dict(required=False, default='Linux64'), - query=dict(required=False, default='versionInfo'), + url=dict( + required=True + ), + get=dict( + required=True + ), + engine=dict( + required=False + ), + server=dict( + required=False + ), + updaterVersion=dict( + required=False + ), + version=dict( + required=False + ), + platform=dict( + required=False, + default='Linux64' + ), + query=dict( + required=False, + default='versionInfo' + ), ), supports_check_mode=False, ) @@ -327,6 +333,8 @@ def main(): api = UrbanterrorAPI(module) result = api.run() + module.log(msg=f"= result : {result}") + module.exit_json(**result) diff --git a/library/urbanterror_installer.py b/library/urbanterror_installer.py index cb7a539..1e85b7c 100644 --- a/library/urbanterror_installer.py +++ b/library/urbanterror_installer.py @@ -70,19 +70,23 @@ def run(self): """ """ - return_code, data = self.__api_data() + return_code, data = self.download_manifest() - if(return_code == 200): + if return_code == 200: """ """ - server_list = self.__parse_server_list(data) + server_list = self.__parse_serverlist_section(data) self.download_server = server_list.get('url') - result = self.__parse_files(data) + result_data = self.__parse_files_section(data, 0) + result_engine = self.__parse_files_section(data, 1) + + result = result_engine + result_data + count_full = len(result) - file_list = self.__check_data(result) + file_list = self.verify_data_integrity(result) count_download = len(file_list) if count_download > 0: @@ -92,26 +96,26 @@ def run(self): return dict( changed=True, failed=False, - msg="{0} files available, {1} downloaded".format(count_full, count_download) + msg=f"{count_full} files available, {count_download} new downloaded." ) else: return dict( changed=True, failed=True, - msg="{0} files should be available, but not all can be downloaded".format(count_full) + msg=f"{count_full} files should be available, but not all can be downloaded." ) - file_list = self.__check_data(result) + file_list = self.verify_data_integrity(result) else: return dict( changed=False, failed=False, - msg="{0} files up-to-date".format(count_full) + msg=f"{count_full} files up-to-date." ) return dict( failed = True, - msg="no API data available" + msg="no manifest data available" ) def md5(self, fname): @@ -121,30 +125,39 @@ def md5(self, fname): hash_md5.update(chunk) return hash_md5.hexdigest() - def __check_data(self, data): + def verify_data_integrity(self, data): """ """ need_download = [] for f in data: - directory = f.get('FileDir') - # url = f.get('FileUrl')[-1:][0] + # self.module.log(msg="------------------------------------------------------------------") + # self.module.log(msg=f" {f}") + directory = f.get('FileDir', "") + # file_url = f.get('FileUrl') file_name = f.get('FileName') file_size = f.get('FileSize') checksum = f.get('FileMD5') + # self.module.log(msg=f" directory : {directory}") + # self.module.log(msg=f" file_name : {file_name}") + # self.module.log(msg=f" file_size : {file_size}") + # self.module.log(msg=f" file_url : {file_url}") + # self.module.log(msg=f" checksum : {checksum}") + # self.module.log(msg="------------------------------------------------------------------") + + if directory: + dest_file = os.path.join(self.destination, directory, file_name) + else: + dest_file = os.path.join(self.destination, file_name) - dest_file = os.path.join(self.destination, directory, file_name) + # self.module.log(msg=f" dest_file : {dest_file}") _size, _checksum = self.__file_info(dest_file) if int(_size) == int(file_size) and _checksum == checksum: - self.module.log( - msg=" - {0} - file okay".format(dest_file) - ) + self.module.log(msg=f" - {dest_file} - file size and checksum okay") else: - self.module.log( - msg=" - {0} - missmatch ...".format(dest_file) - ) + self.module.log(msg=f" - {dest_file} - file size or checksum missmatch ...") need_download.append(f) return need_download @@ -152,41 +165,55 @@ def __check_data(self, data): def __download(self, data): """ """ - self.module.log("download files") - should_counter = 0 is_counter = len(data) for f in data: + # self.module.log(msg="------------------------------------------------------------------") + # self.module.log(msg=f" {f}") + directory = f.get('FileDir') - url = f.get('FileUrl')[-1:][0] + file_url = f.get('FileUrl') file_name = f.get('FileName') file_size = f.get('FileSize') checksum = f.get('FileMD5') + # self.module.log(msg=f" directory : {directory}") + # self.module.log(msg=f" file_name : {file_name}") + # self.module.log(msg=f" file_size : {file_size}") + # self.module.log(msg=f" file_url : {file_url}") + # self.module.log(msg=f" checksum : {checksum}") + # self.module.log(msg="------------------------------------------------------------------") + # self.module.log( - # msg=" - {} : {} : {}".format(file_name, file_size, checksum) + # msg=f" - {file_name} : {file_size} : {checksum}" # ) - try: - # Create target Directory - os.mkdir(os.path.join(self.destination, directory)) - except FileExistsError: - pass + if isinstance(file_url, list): + file_url = file_url[-1:][0] - dest_file = os.path.join(self.destination, directory, file_name) + # Create target Directory + if directory: + try: + os.mkdir(os.path.join(self.destination, directory)) + except FileExistsError: + pass + + dest_file = os.path.join(self.destination, directory, file_name) + else: + dest_file = os.path.join(self.destination, file_name) + + # self.module.log(msg=f" dest_file : {dest_file}") with open(dest_file, "wb") as file: - response = requests.get("{}/{}".format(self.download_server, url)) + response = requests.get(f"{self.download_server}/{file_url}") file.write(response.content) file.close() _size, _checksum = self.__file_info(dest_file) if int(_size) == int(file_size) and _checksum == checksum: - self.module.log( - msg=" -> successful" - ) + self.module.log(msg=f" - {dest_file} - successfully downloaded") should_counter = should_counter + 1 @@ -202,11 +229,11 @@ def __file_info(self, file_name): return _size, _checksum - def __parse_files(self, data): + def __parse_files_section(self, data, index=0): """ """ # result = {} - files = data.get('Files')[0].get('File') + files = data.get('Files')[int(index)].get('File') try: _list = json.loads( @@ -215,13 +242,13 @@ def __parse_files(self, data): except Exception as e: self.module.log( - msg=" exception: {} ({})".format(e, type(e)) + msg=f" exception: {e} ({type(e)})" ) pass return _list - def __parse_server_list(self, data): + def __parse_serverlist_section(self, data): """ """ result = {} @@ -247,10 +274,11 @@ def __parse_server_list(self, data): return result - def __api_data(self): + def download_manifest(self): """ """ updater_data = dict() + output_dict = dict() payload = { 'platform': self.platform, @@ -261,53 +289,47 @@ def __api_data(self): 'server': self.server, 'updaterVersion': self.updaterVersion } + # self.module.log(msg=f" payload: {payload}") - self.module.log(msg=" payload: {}".format(payload)) + code, ret = self.__call_url(data=payload) - code, ret = self.__call_url( - data=payload - ) - - if(code == 200 and len(ret) != 0): + if code == 200 and len(ret) != 0: import xmltodict - # obj = untangle.parse(XML) - obj = xmltodict.parse( - ret - ) + obj = xmltodict.parse(ret) updater_data = obj['Updater'] + # convert an OrderedDict to an regular dict + output_dict = json.loads(json.dumps(updater_data)) - return code, updater_data + # self.module.log(msg=f"{type(output_dict)}") + # self.module.log(msg=f"{json.dumps(output_dict, indent=2, sort_keys=True)}") + + return code, output_dict def __call_url(self, method='POST', data=None): """ """ - headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' } - self.module.log(msg=" data : {}".format(data)) - self.module.log(msg=" headers: {}".format(headers)) - try: - if(method == 'POST'): + if method == 'POST': ret = requests.post( self.url, data=data, headers=headers, verify=False ) - else: print("unsupported") ret.raise_for_status() - self.module.log(msg="------------------------------------------------------------------") - # self.module.log(msg=" text : {}".format(ret.text)) - self.module.log(msg=" headers : {}".format(ret.headers)) - self.module.log(msg=" code : {}".format(ret.status_code)) - self.module.log(msg="------------------------------------------------------------------") + # self.module.log(msg="------------------------------------------------------------------") + # #self.module.log(msg=f" text : {ret.text}") + # self.module.log(msg=f" headers : {ret.headers}") + # self.module.log(msg=f" code : {ret.status_code}") + # self.module.log(msg="------------------------------------------------------------------") return ret.status_code, ret.text @@ -341,6 +363,8 @@ def main(): api = UrbanterrorInstaller(module) result = api.run() + module.log(msg=f"= result : {result}") + module.exit_json(**result) diff --git a/meta/main.yml b/meta/main.yml index fd911e8..43d5033 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -8,16 +8,19 @@ galaxy_info: description: urbanterror license: "GPLv3" - min_ansible_version: 2.10 + min_ansible_version: "2.10" platforms: - name: Debian versions: - - 10 - - 11 + # 10 + - buster + # 11 + - bullseye - name: Ubuntu versions: - - 20.04 + # 20.04 + - focal dependencies: [] diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 2086fee..5fef1ea 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -23,8 +23,8 @@ platforms: provisioner: name: ansible - # ansible_args: - # - --diff + ansible_args: + - --diff # - -vv config_options: defaults: diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py index c1f6d20..00c52ed 100644 --- a/molecule/default/tests/test_default.py +++ b/molecule/default/tests/test_default.py @@ -13,36 +13,74 @@ def base_directory(): + """ + """ cwd = os.getcwd() - if('group_vars' in os.listdir(cwd)): + if 'group_vars' in os.listdir(cwd): directory = "../.." molecule_directory = "." else: directory = "." - molecule_directory = "molecule/{}".format(os.environ.get('MOLECULE_SCENARIO_NAME')) + molecule_directory = f"molecule/{os.environ.get('MOLECULE_SCENARIO_NAME')}" return directory, molecule_directory +def read_ansible_yaml(file_name, role_name): + """ + """ + read_file = None + + for e in ["yml", "yaml"]: + test_file = "{}.{}".format(file_name, e) + if os.path.isfile(test_file): + read_file = test_file + break + + return f"file={read_file} name={role_name}" + + @pytest.fixture() def get_vars(host): """ - + parse ansible variables + - defaults/main.yml + - vars/main.yml + - vars/${DISTRIBUTION}.yaml + - molecule/${MOLECULE_SCENARIO_NAME}/group_vars/all/vars.yml """ base_dir, molecule_dir = base_directory() - - file_defaults = "file={}/defaults/main.yml name=role_defaults".format(base_dir) - file_vars = "file={}/vars/main.yml name=role_vars".format(base_dir) - file_molecule = "file={}/group_vars/all/vars.yml name=test_vars".format(molecule_dir) - - defaults_vars = host.ansible("include_vars", file_defaults).get("ansible_facts").get("role_defaults") - vars_vars = host.ansible("include_vars", file_vars).get("ansible_facts").get("role_vars") - molecule_vars = host.ansible("include_vars", file_molecule).get("ansible_facts").get("test_vars") + distribution = host.system_info.distribution + operation_system = None + + if distribution in ['debian', 'ubuntu']: + operation_system = "debian" + elif distribution in ['redhat', 'ol', 'centos', 'rocky', 'almalinux']: + operation_system = "redhat" + elif distribution in ['arch', 'artix']: + operation_system = f"{distribution}linux" + + # print(" -> {} / {}".format(distribution, os)) + # print(" -> {}".format(base_dir)) + + file_defaults = read_ansible_yaml(f"{base_dir}/defaults/main", "role_defaults") + file_vars = read_ansible_yaml(f"{base_dir}/vars/main", "role_vars") + file_distibution = read_ansible_yaml(f"{base_dir}/vars/{operation_system}", "role_distibution") + file_molecule = read_ansible_yaml(f"{molecule_dir}/group_vars/all/vars", "test_vars") + # file_host_molecule = read_ansible_yaml("{}/host_vars/{}/vars".format(base_dir, HOST), "host_vars") + + defaults_vars = host.ansible("include_vars", file_defaults).get("ansible_facts").get("role_defaults") + vars_vars = host.ansible("include_vars", file_vars).get("ansible_facts").get("role_vars") + distibution_vars = host.ansible("include_vars", file_distibution).get("ansible_facts").get("role_distibution") + molecule_vars = host.ansible("include_vars", file_molecule).get("ansible_facts").get("test_vars") + # host_vars = host.ansible("include_vars", file_host_molecule).get("ansible_facts").get("host_vars") ansible_vars = defaults_vars ansible_vars.update(vars_vars) + ansible_vars.update(distibution_vars) ansible_vars.update(molecule_vars) + # ansible_vars.update(host_vars) templar = Templar(loader=DataLoader(), variables=ansible_vars) result = templar.template(ansible_vars, fail_on_undefined=False) @@ -52,17 +90,30 @@ def get_vars(host): @pytest.mark.parametrize("dirs", [ "/opt/urbanterror", + "/opt/urbanterror/q3ut4" ]) def test_directories(host, dirs): d = host.file(dirs) assert d.is_directory - assert d.exists @pytest.mark.parametrize("files", [ "/opt/urbanterror/server.sh", + "/opt/urbanterror/updater-cfg", + "/opt/urbanterror/Quake3-UrT.x86_64", + "/opt/urbanterror/Quake3-UrT-Ded.x86_64", + "/opt/urbanterror/q3ut4/server.cfg", + "/opt/urbanterror/q3ut4/mapcycle.txt", + "/opt/urbanterror/q3ut4/zUrT43_001.pk3", + "/opt/urbanterror/q3ut4/zUrT43_021.pk3", + "/opt/urbanterror/q3ut4/ut4_jumpents.pk3", ]) def test_files(host, files): f = host.file(files) - assert f.exists assert f.is_file + + +def test_service(host, get_vars): + service = host.service("urbanterror") + assert service.is_enabled + assert service.is_running diff --git a/tasks/install.yaml b/tasks/install.yaml index 8dbd426..c5ab25d 100644 --- a/tasks/install.yaml +++ b/tasks/install.yaml @@ -5,14 +5,24 @@ url: "http://www.urbanterror.info/api/updaterv4" destination: "{{ urbanterror_directory }}" platform: Linux64 - updaterVersion: '4.0.3' + updaterVersion: "{{ urbanterror_version }}" register: version_info + notify: + - restart urbanterror - name: info debug: msg: - "{{ version_info }}" +- name: make sure that the engine is executable + file: + path: "{{ urbanterror_directory }}/{{ item }}" + mode: 0750 + loop: + - Quake3-UrT-Ded.x86_64 + - Quake3-UrT.x86_64 + - name: install server.sh template: src: server.sh.j2 @@ -23,6 +33,7 @@ get_url: url: "{{ item.src }}" dest: "{{ urbanterror_directory }}/q3ut4/" + mode: 0640 register: _download_archive until: _download_archive is succeeded retries: 5 @@ -31,22 +42,12 @@ loop_control: label: "{{ item.name }}" -- name: create server config - template: - src: server.cfg.j2 - dest: "{{ urbanterror_directory }}/q3ut4/server.cfg" - mode: 0660 - -- name: create mapcycle - template: - src: mapcycle.txt.j2 - dest: "{{ urbanterror_directory }}/q3ut4/mapcycle.txt" - mode: 0660 - - name: create systemd unit file template: src: urbanterror.service.j2 dest: /etc/systemd/system/urbanterror.service mode: 0644 + notify: + - reload systemd ... diff --git a/tasks/main.yml b/tasks/main.yml index 9fd3023..69967ba 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,8 +1,18 @@ --- -- include_tasks: prepare.yaml -- include_tasks: install.yaml -- include_tasks: service.yaml -- include_tasks: write_facts.yaml +- name: prepare + include_tasks: prepare.yaml + +- name: install + include_tasks: install.yaml + +- name: configure + include_tasks: configure.yaml + +- name: write facts + include_tasks: write_facts.yaml + +- name: service + include_tasks: service.yaml ... diff --git a/tasks/prepare.yaml b/tasks/prepare.yaml index b48149a..543ef72 100644 --- a/tasks/prepare.yaml +++ b/tasks/prepare.yaml @@ -38,16 +38,15 @@ dest: "{{ urbanterror_directory }}/updater.sh" mode: 0750 -- name: urbanterror api +- name: get urbanterror engine list urbanterror_api: url: "http://www.urbanterror.info/api/updaterv4/" get: engine_list platform: Linux64 - updaterVersion: '4.0.3' - # query: 'versionInfo' + updaterVersion: "{{ urbanterror_version }}" register: version_info -- name: info +- name: engine list debug: msg: - "{{ version_info }}" diff --git a/templates/server.sh.j2 b/templates/server.sh.j2 index 9d543f1..51cfe87 100644 --- a/templates/server.sh.j2 +++ b/templates/server.sh.j2 @@ -1,9 +1,13 @@ #!/usr/bin/env bash -set -e +set -x +# set -e -#while true -#do +urbanterror_bin={{ urbanterror_directory }}/{{ urbanterror_binary }} + + +if [ -n "${urbanterror_bin}" ] && [ -f "${urbanterror_bin}" ] +then {{ urbanterror_directory }}/{{ urbanterror_binary }} \ +set fs_game q3ut4 \ +set fs_basepath {{ urbanterror_directory }} \ @@ -13,6 +17,10 @@ set -e +set net_port {{ urbanterror_bind_port }} \ +set com_hunkmegs 128 \ +exec server.cfg > {{ urbanterror_directory }}/server.out 2>&1 +else + echo "ERROR: missing binary ${urbanterror_bin}" + exit 2 +fi # echo "server crashed on `date`" > {{ urbanterror_directory }}/last_crash.txt # done diff --git a/templates/urbanterror.service.j2 b/templates/urbanterror.service.j2 index 4f59ec2..dd9373e 100644 --- a/templates/urbanterror.service.j2 +++ b/templates/urbanterror.service.j2 @@ -1,15 +1,19 @@ [Unit] -Description=Urban Terror Server -After=network.target -Before=shutdown.target reboot.target halt.target -# OnFailure=status-send-email@%n.service +Description = Urban Terror Server +After = network.target +Before = shutdown.target reboot.target halt.target +# OnFailure = status-send-email@%n.service [Service] -ExecStart=/usr/bin/screen -m -d -S UrT-Server sh {{ urbanterror_directory }}/server.sh -ExecStop=/usr/bin/screen -S UrT-Server -X quit -ExecReload=/usr/bin/screen -S UrT-Server -X quit && /usr/bin/screen -m -d -S UrT-Server sh {{ urbanterror_directory }}/server.sh -Type=forking -Restart=on-failure +WorkingDirectory = {{ urbanterror_directory }} + +ExecStart = /usr/bin/screen -m -d -S UrT-Server sh {{ urbanterror_directory }}/server.sh +ExecStop = /usr/bin/screen -S UrT-Server -X quit +ExecReload = /usr/bin/screen -S UrT-Server -X quit && /usr/bin/screen -m -d -S UrT-Server sh {{ urbanterror_directory }}/server.sh +Type = forking + +SyslogIdentifier = urbanterror +Restart = on-failure [Install] -WantedBy=multi-user.target +WantedBy = multi-user.target diff --git a/test-requirements.txt b/test-requirements.txt index b6b224c..813e694 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,10 +1,11 @@ ansible-lint==5.4.0 -molecule==3.6.1 -molecule-docker==1.1.0 -docker==5.0.0 -yamllint==1.26.3 -flake8==3.9.2 -pytest==6.2.5 -pytest-testinfra==6.4.0 -tox==3.24.3 -tox-gh-actions==2.6.0 +molecule==4.0.1 +molecule-docker==2.0.0 +docker==5.0.3 +yamllint==1.27.1 +flake8==4.0.1 +pytest==7.1.2 +pytest-testinfra==6.8.0 +tox==3.25.1 +tox-gh-actions==2.9.1 +netaddr==0.8.0 diff --git a/tox.ini b/tox.ini index c2846f5..c44d62d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,33 +1,25 @@ [tox] -minversion = 1.8 +minversion = 3.25 toxworkdir = /tmp/.tox/ -envlist = py{39,310}-ansible{29,210} +envlist = ansible_{2.9,2.10,3.4,4.10,5.1,5.2,6.1} skipsdist = true -[gh-actions] -ansible = - 2.9: ansible29 - 2.10: ansible210 - -python = - 3.9: py39 - 3.10: py310 - [testenv] passenv = * deps = -r test-requirements.txt - ansible29: ansible>=2.9,<2.10 - ansible210: ansible>=2.10,<2.11 - ansible340: ansible>=3.4,<3.5 - ansible410: ansible>=4.10,<4.11 - ansible510: ansible>=5.1,<5.2 - ansible520: ansible>=5.2,<5.3 + ansible_2.9: ansible>=2.9,<2.10 + ansible_2.10: ansible>=2.10,<2.11 + ansible_3.4: ansible>=3.4,<3.5 + ansible_4.10: ansible>=4.10,<4.11 + ansible_5.1: ansible>=5.1,<5.2 + ansible_5.2: ansible>=5.2,<5.3 + ansible_6.1: ansible>=6.1,<6.2 commands_pre = - /usr/bin/find {toxinidir} -type f -not -path '{toxinidir}/.tox/*' -path '*/__pycache__/*' -name '*.py[c|o]' -delete + /usr/bin/find {toxinidir} -type f -not -path '{toxworkdir}/*' -path '*/__pycache__/*' -name '*.py[c|o]' -delete /bin/sh -c '/usr/bin/find {homedir}/.cache -type d -path "*/molecule_*" -exec rm -rfv \{\} +;' commands = diff --git a/vars/main.yml b/vars/main.yml index 27ece47..bf029e8 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -9,6 +9,9 @@ urbanterror_dependencies: - python3-urllib3 - python3-requests - python3-xmltodict + # + - libsdl1.2debian + - libxxf86vm1 urbanterror_server_config: "{{ urbanterror_install_path }}/q3ut4/server.cfg"