├── .gitattributes ├── collections └── ansible_collections │ └── sample_namespace │ └── sample_collection │ ├── roles │ └── backup_file │ │ ├── tests │ │ ├── inventory │ │ └── test.yml │ │ ├── vars │ │ └── main.yml │ │ ├── handlers │ │ └── main.yml │ │ ├── requirements.yml │ │ ├── defaults │ │ └── main.yml │ │ ├── meta │ │ └── main.yml │ │ ├── .yamllint │ │ ├── tasks │ │ └── main.yml │ │ └── README.md │ ├── extensions │ └── molecule │ │ └── default │ │ ├── requirements.yml │ │ ├── converge.yml │ │ ├── INSTALL.rst │ │ ├── templates │ │ └── deployment.yml │ │ ├── prepare.yml │ │ ├── destroy.yml │ │ ├── molecule.yml │ │ ├── create.yml │ │ └── verify.yml │ ├── README.md │ ├── plugins │ └── README.md │ ├── meta │ └── runtime.yml │ └── galaxy.yml ├── .vscode ├── extensions.json └── settings.json ├── .code-workspace ├── syntax_highlighting_demo.yml ├── .ansible-lint ├── .github └── workflows │ └── ansible-lint.yml ├── .yamllint ├── .pre-commit-config.yaml ├── devfile.yaml └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | CODEOWNERS export-ignore 2 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/tests/inventory: -------------------------------------------------------------------------------- 1 | ubi8-int 2 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for backup_file 3 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for backup_file 3 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Simple test case 3 | hosts: all 4 | connection: community.okd.oc 5 | roles: 6 | - backup_file 7 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-python.python", 4 | "redhat.ansible", 5 | "redhat.vscode-openshift-connector", 6 | "ms-python.black-formatter" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: kubernetes.core 4 | version: 2.4.0 5 | - name: community.okd 6 | version: 2.3.0 7 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: kubernetes.core 4 | version: 2.4.0 5 | - name: community.okd 6 | version: 2.3.0 7 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/README.md: -------------------------------------------------------------------------------- 1 | # Ansible Collection - example.collection 2 | 3 | An example collection to show off how to do Ansible collection and role development in Red Hat OpenShift Dev Spaces. 4 | -------------------------------------------------------------------------------- /.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "ansible.lightspeed.suggestions.enabled": true, 4 | "ansible.lightspeed.enabled": true 5 | }, 6 | "folders": [ 7 | { 8 | "name": "ansible-devspaces-demo", 9 | "path": "/projects/ansible-devspaces-demo" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | gather_facts: true 5 | connection: community.okd.oc 6 | tasks: 7 | - name: "Include backup_file" 8 | ansible.builtin.include_role: 9 | name: "sample_namespace.sample_collection.backup_file" 10 | -------------------------------------------------------------------------------- /syntax_highlighting_demo.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is a sample playbook with linting issues. 3 | # This filename is excluded from ansible-lint so that the GitHub pipeline will pass. 4 | # Copy or rename this file to try ansible-lint and/or pre-commit. 5 | - name: Hello World Playbook 6 | hosts: all 7 | gather_facts: false 8 | tasks: 9 | - name: Print Hello World 10 | ansible.builtin.debug: 11 | msg: "Hello World" 12 | - debug: 13 | msg: "I am poorly written" 14 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/INSTALL.rst: -------------------------------------------------------------------------------- 1 | *********************************** 2 | Delegated driver installation guide 3 | *********************************** 4 | 5 | Requirements 6 | ============ 7 | 8 | This driver is delegated to the developer. Up to the developer to implement 9 | requirements. 10 | 11 | Install 12 | ======= 13 | 14 | This driver is delegated to the developer. Up to the developer to implement 15 | requirements. 16 | -------------------------------------------------------------------------------- /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | mock_modules: 3 | - community.okd.k8s 4 | 5 | mock_roles: 6 | - backup_file 7 | 8 | exclude_paths: 9 | - devfile.yml 10 | - syntax_highlighting_demo.yml 11 | - collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/molecule 12 | - collections/ansible_collections/sample_namespace/sample_collection/extensions 13 | 14 | warn_list: 15 | - galaxy[no-changelog] # TODO: Implement changelog. 16 | - schema[meta-runtime] # TODO: Implement meta/runtime.yml 17 | -------------------------------------------------------------------------------- /.github/workflows/ansible-lint.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/ansible-lint.yml 2 | name: ansible-lint 3 | on: 4 | pull_request: 5 | branches: 6 | - 'devspaces-[0-9].[0-9]+-rhel-8' 7 | - devspaces-3-rhel-8 8 | jobs: 9 | build: 10 | name: Ansible Lint # Naming the build is important to use it as a status check 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Run ansible-lint 15 | uses: ansible/ansible-lint@main # or version tag instead of 'main' 16 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for backup_file 3 | backup_file_source: '/etc/hosts' 4 | backup_file_dest_folder: '/tmp/backups' 5 | backup_file_dest_suffix: '.bak' 6 | backup_file_dest_dir_owner: "{{ ansible_user_id }}" 7 | backup_file_dest_dir_group: "{{ ansible_user_gid }}" 8 | backup_file_dest_dir_mode: '0750' 9 | backup_file_dest_owner: "{{ ansible_user_id }}" 10 | backup_file_dest_group: "{{ ansible_user_gid }}" 11 | backup_file_dest_mode: '0640' 12 | backup_file_remote_source: true 13 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | author: jeffcpullen 3 | namespace: demo 4 | description: "This is an example of a non-priviledged role using kubernetes as the driver and connection method" 5 | company: Red Hat 6 | 7 | license: GPL-3 8 | 9 | min_ansible_version: '2.15' 10 | 11 | platforms: 12 | - name: Fedora 13 | versions: 14 | - all 15 | - name: EL 16 | versions: 17 | - all 18 | 19 | galaxy_tags: 20 | - system 21 | - ansible 22 | - automation 23 | 24 | dependencies: [] 25 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.yaml": "ansible", 4 | "*.yml": "ansible" 5 | }, 6 | "ansible.ansible.path": "/usr/local/bin/ansible", 7 | "ansible.python.interpreterPath": "/bin/python", 8 | "ansible.ansible.useFullyQualifiedCollectionNames": true, 9 | "ansible.ansibleNavigator.path": "ansible-navigator", 10 | "ansible.completion.provideModuleOptionAliases": true, 11 | "ansible.completion.provideRedirectModules": true, 12 | "ansible.validation.enabled": true, 13 | "ansible.validation.lint.enabled": true, 14 | "ansible.validation.lint.path": "/usr/local/bin/ansible-lint" 15 | } 16 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/templates/deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ item.name }}" 5 | namespace: "{{ backup_file_molecule_namespace }}" 6 | labels: 7 | app: "molecule-test-container" 8 | spec: 9 | containers: 10 | - name: molecule 11 | image: "{{ item.image }}" 12 | workingDir: "{{ item.workingDir }}" 13 | tmpfs: 14 | - /run 15 | - /tmp 16 | volumes: 17 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 18 | capabilities: 19 | - SYS_ADMIN 20 | command: 21 | - "/usr/sbin/init" 22 | pre_build_image: true 23 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: disable 19 | comments-indentation: disable 20 | document-start: disable 21 | empty-lines: 22 | max: 3 23 | level: error 24 | hyphens: 25 | level: error 26 | indentation: disable 27 | key-duplicates: enable 28 | line-length: disable 29 | new-line-at-end-of-file: disable 30 | new-lines: 31 | type: unix 32 | trailing-spaces: disable 33 | truthy: disable 34 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: 19 | min-spaces-from-content: 1 20 | comments-indentation: false 21 | octal-values: 22 | forbid-implicit-octal: true 23 | forbid-explicit-octal: true 24 | document-start: disable 25 | empty-lines: 26 | max: 3 27 | level: error 28 | hyphens: 29 | level: error 30 | indentation: enable 31 | key-duplicates: enable 32 | line-length: disable 33 | new-line-at-end-of-file: enable 34 | new-lines: 35 | type: unix 36 | trailing-spaces: enable 37 | truthy: enable 38 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: 'https://github.com/pre-commit/pre-commit-hooks' 4 | rev: v4.5.0 5 | hooks: 6 | - id: check-added-large-files 7 | - id: check-merge-conflict 8 | - id: end-of-file-fixer 9 | - id: trailing-whitespace 10 | exclude: syntax_highlighting_demo.yml 11 | - id: no-commit-to-branch 12 | 13 | - repo: 'https://github.com/ansible-community/ansible-lint.git' 14 | rev: v6.22.1 15 | hooks: 16 | - id: ansible-lint 17 | pass_filenames: false 18 | always_run: true 19 | entry: "ansible-lint" 20 | args: 21 | - "--profile=production" 22 | - "-c=.ansible-lint" 23 | additional_dependencies: 24 | - "ansible-core>=2.13" 25 | - "yamllint>=1.29,<2.0" 26 | 27 | - repo: https://github.com/gitleaks/gitleaks 28 | rev: v8.16.1 29 | hooks: 30 | - id: gitleaks 31 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for backup_file 3 | 4 | - name: Ping the host 5 | ansible.builtin.ping: 6 | 7 | - name: Backup File | Create backup directory 8 | ansible.builtin.file: 9 | path: "{{ backup_file_dest_folder }}" 10 | state: directory 11 | owner: "{{ backup_file_dest_dir_owner }}" 12 | group: "{{ backup_file_dest_dir_group }}" 13 | mode: "{{ backup_file_dest_dir_mode }}" 14 | 15 | - name: Backup File | Copy source file to backup destination 16 | ansible.builtin.copy: 17 | src: "{{ backup_file_source }}" 18 | dest: "{{ backup_file_dest_folder }}/{{ backup_file_source | basename }}{{ backup_file_dest_suffix }}" 19 | owner: "{{ backup_file_dest_owner }}" 20 | group: "{{ backup_file_dest_group }}" 21 | mode: "{{ backup_file_dest_mode }}" 22 | remote_src: "{{ backup_file_remote_source }}" 23 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/plugins/README.md: -------------------------------------------------------------------------------- 1 | # Collections Plugins Directory 2 | 3 | This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that 4 | is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that 5 | would contain module utils and modules respectively. 6 | 7 | Here is an example directory of the majority of plugins currently supported by Ansible: 8 | 9 | ``` 10 | └── plugins 11 | ├── action 12 | ├── become 13 | ├── cache 14 | ├── callback 15 | ├── cliconf 16 | ├── connection 17 | ├── filter 18 | ├── httpapi 19 | ├── inventory 20 | ├── lookup 21 | ├── module_utils 22 | ├── modules 23 | ├── netconf 24 | ├── shell 25 | ├── strategy 26 | ├── terminal 27 | ├── test 28 | └── vars 29 | ``` 30 | 31 | A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.14/plugins/plugins.html). 32 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | tasks: 8 | 9 | - name: Store user ENVs 10 | ansible.builtin.set_fact: 11 | molecule_user_home_dir: "{{ lookup('ansible.builtin.env', 'HOME') }}" 12 | molecule_user_path: "{{ lookup('ansible.builtin.env', 'PATH') }}" 13 | 14 | - name: Create local bin directory 15 | ansible.builtin.file: 16 | path: "{{ molecule_user_home_dir }}/bin" 17 | state: directory 18 | mode: 0770 19 | 20 | - name: Add another bin dir to system-wide $PATH. 21 | ansible.builtin.lineinfile: 22 | path: "{{ molecule_user_home_dir }}/.bashrc" 23 | line: 'PATH=$PATH:{{ molecule_user_home_dir }}/bin' 24 | state: present 25 | 26 | - name: Ensure python dependencies are installed 27 | ansible.builtin.pip: 28 | name: "{{ backup_file_molecule_pip_dependencies }}" 29 | state: present 30 | when: backup_file_molecule_pip_dependencies is defined 31 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/destroy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Destroy 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | tasks: 8 | # Developer must implement. 9 | 10 | - name: Destroy molecule containers 11 | community.okd.k8s: 12 | kubeconfig: "{{ lookup('ansible.builtin.env', 'HOME') }}/.kube/config" 13 | state: absent 14 | definition: "{{ lookup('template', 'templates/deployment.yml') | from_yaml }}" 15 | wait: true 16 | register: server 17 | with_items: "{{ molecule_yml.platforms }}" 18 | 19 | # Mandatory configuration for Molecule to function. 20 | 21 | - name: Populate instance config 22 | ansible.builtin.set_fact: 23 | instance_conf: {} 24 | 25 | - name: Dump instance config # noqa: no-handler 26 | ansible.builtin.copy: 27 | content: | 28 | # Molecule managed 29 | 30 | {{ instance_conf | to_json | from_json | to_yaml }} 31 | dest: "{{ molecule_instance_config }}" 32 | mode: 0600 33 | when: server.changed | default(false) | bool 34 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | options: 5 | requirements-file: requirements.yml 6 | driver: 7 | name: default 8 | options: 9 | managed: true 10 | ansible_connection_options: 11 | connection: local 12 | platforms: 13 | - name: molecule-ubi8-python-1 14 | image: registry.access.redhat.com/ubi8/python-39@sha256:301fec66443f80c3cc507ccaf72319052db5a1dc56deb55c8f169011d4bbaacb 15 | workingDir: '/tmp' 16 | provisioner: 17 | name: ansible 18 | # Failing to write the ansible into /.ansible/tmp 19 | config_options: 20 | defaults: 21 | remote_tmp: '/tmp' 22 | # This just says go back a directory and thats your roles path 23 | # You can also provide this via pipeline with something like this 24 | # ANSIBLE_ROLES_PATH: $COLLECTION_ROLES 25 | 26 | # COLLECTIONS_PATH: ${PROJECT_SOURCE} 27 | # ANSIBLE_ROLES_PATH: ${PROJECT_SOURCE}/${backup_file_molecule_namespace} 28 | inventory: 29 | group_vars: 30 | all: 31 | backup_file_molecule_namespace: ${DEVWORKSPACE_NAMESPACE} 32 | backup_file_molecule_pip_dependencies: 33 | - kubernetes 34 | verifier: 35 | name: ansible 36 | scenario: 37 | name: default 38 | test_sequence: 39 | - dependency 40 | - syntax 41 | - create 42 | - converge 43 | - idempotence 44 | - verify 45 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/meta/runtime.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Collections must specify a minimum required ansible version to upload 3 | # to galaxy 4 | # requires_ansible: '>=2.9.10' 5 | 6 | # Content that Ansible needs to load from another location or that has 7 | # been deprecated/removed 8 | # plugin_routing: 9 | # action: 10 | # redirected_plugin_name: 11 | # redirect: ns.col.new_location 12 | # deprecated_plugin_name: 13 | # deprecation: 14 | # removal_version: "4.0.0" 15 | # warning_text: | 16 | # See the porting guide on how to update your playbook to 17 | # use ns.col.another_plugin instead. 18 | # removed_plugin_name: 19 | # tombstone: 20 | # removal_version: "2.0.0" 21 | # warning_text: | 22 | # See the porting guide on how to update your playbook to 23 | # use ns.col.another_plugin instead. 24 | # become: 25 | # cache: 26 | # callback: 27 | # cliconf: 28 | # connection: 29 | # doc_fragments: 30 | # filter: 31 | # httpapi: 32 | # inventory: 33 | # lookup: 34 | # module_utils: 35 | # modules: 36 | # netconf: 37 | # shell: 38 | # strategy: 39 | # terminal: 40 | # test: 41 | # vars: 42 | 43 | # Python import statements that Ansible needs to load from another location 44 | # import_redirection: 45 | # ansible_collections.ns.col.plugins.module_utils.old_location: 46 | # redirect: ansible_collections.ns.col.plugins.module_utils.new_location 47 | 48 | # Groups of actions/modules that take a common set of options 49 | # action_groups: 50 | # group_name: 51 | # - module1 52 | # - module2 53 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | tasks: 8 | 9 | - name: Create molecule instance as containers 10 | community.okd.k8s: 11 | kubeconfig: "{{ lookup('ansible.builtin.env', 'HOME') }}/.kube/config" 12 | state: present 13 | definition: "{{ lookup('template', 'templates/deployment.yml') | from_yaml }}" 14 | wait: true 15 | register: server 16 | with_items: "{{ molecule_yml.platforms }}" 17 | 18 | - name: Debug molecule creations 19 | ansible.builtin.debug: 20 | var: server 21 | 22 | - name: Store container information # noqa: no-handler 23 | when: server.changed | default(false) | bool 24 | block: 25 | 26 | - name: Populate instance config dict 27 | ansible.builtin.set_fact: 28 | instance_conf_dict: { 29 | 'instance': "{{ item.result.status.containerStatuses[0].name }}", 30 | } 31 | with_items: "{{ server.results }}" 32 | register: instance_config_dict 33 | 34 | - name: Convert instance config dict to a list 35 | ansible.builtin.set_fact: 36 | instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}" 37 | 38 | - name: Dump instance config 39 | ansible.builtin.copy: 40 | content: | 41 | # Molecule managed 42 | 43 | {{ instance_conf | to_json | from_json | to_yaml }} 44 | dest: "{{ molecule_instance_config }}" 45 | mode: 0600 46 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/galaxy.yml: -------------------------------------------------------------------------------- 1 | ### REQUIRED 2 | # The namespace of the collection. This can be a company/brand/organization or product namespace under which all 3 | # content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with 4 | # underscores or numbers and cannot contain consecutive underscores 5 | namespace: example 6 | 7 | # The name of the collection. Has the same character restrictions as 'namespace' 8 | name: collection 9 | 10 | # The version of the collection. Must be compatible with semantic versioning 11 | version: 1.0.0 12 | 13 | # The path to the Markdown (.md) readme file. This path is relative to the root of the collection 14 | readme: README.md 15 | 16 | # A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) 17 | # @nicks:irc/im.site#channel' 18 | authors: 19 | - your name 20 | 21 | 22 | ### OPTIONAL but strongly recommended 23 | # A short summary description of the collection 24 | description: your collection description 25 | 26 | # Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only 27 | # accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' 28 | license: 29 | - GPL-2.0-or-later 30 | 31 | # The path to the license file for the collection. This path is relative to the root of the collection. This key is 32 | # mutually exclusive with 'license' 33 | license_file: '' 34 | 35 | # A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character 36 | # requirements as 'namespace' and 'name' 37 | tags: [linux, infrastructure] 38 | 39 | # Collections that this collection requires to be installed for it to be usable. The key of the dict is the 40 | # collection label 'namespace.name'. The value is a version range 41 | # L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version 42 | # range specifiers can be set and are separated by ',' 43 | dependencies: {} 44 | 45 | # The URL of the originating SCM repository 46 | repository: http://example.com/repository 47 | 48 | # The URL to any online docs 49 | documentation: http://docs.example.com 50 | 51 | # The URL to the homepage of the collection/project 52 | homepage: http://example.com 53 | 54 | # The URL to the collection issue tracker 55 | issues: http://example.com/issue/tracker 56 | 57 | # A list of file glob-like patterns used to filter any files or directories that should not be included in the build 58 | # artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This 59 | # uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', 60 | # and '.git' are always filtered. Mutually exclusive with 'manifest' 61 | build_ignore: [] 62 | 63 | # A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a 64 | # list of MANIFEST.in style 65 | # L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key 66 | # 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive 67 | # with 'build_ignore' 68 | # manifest: null 69 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file/README.md: -------------------------------------------------------------------------------- 1 | backup_file 2 | ========= 3 | 4 | Sample role to demonstrate running molecule inside of OpenShift Dev Spaces. Molecule is configured to leverage the downstream API to create containers in the user's devspace namespace. This role does not require elevated permissions or modifications to OpenShift. 5 | 6 | Requirements 7 | ------------ 8 | 9 | - The Kubernetes python module is required. This is installed to the DevSpace as part of the molecule prepare stage. 10 | - The 'oc' binary is required. This is installed as part of the molecule prepare stage and added to ~/.bashrc. If you need to run oc commands you can source your bashrc file after running the prepare. `source ~/.bashrc` 11 | - kubernetes.core collection 12 | - community.okd or redhat.openshift collection 13 | - Required collections are included in the requirements.yml file that can be installed with `ansible-galaxy install -r requirements.yml` command 14 | 15 | 16 | Manually installing dependencies (rather than using `molecule prepare`) 17 | ------------- 18 | 19 | Download the 'oc' binary from the downloads route local to the cluster and add to path 20 | 21 | ``` 22 | mkdir $HOME/bin 23 | curl -o $HOME/bin/oc http://downloads.openshift-console.svc.cluster.local/amd64/linux/oc 24 | chmod u+x $HOME/bin/oc 25 | export PATH=$PATH:$HOME/bin 26 | ``` 27 | 28 | OpenShift Token is automatically injected. You can verify this by running the following commands: 29 | 30 | ``` 31 | oc whoami 32 | oc get pods 33 | ``` 34 | 35 | Install the required collections: 36 | 37 | ``` 38 | ansible-galaxy collection install -r demo/backup_file/requirements.yml 39 | ``` 40 | 41 | Role Variables 42 | -------------- 43 | 44 | | Name | Required | Default | Type | Description | 45 | | ------- | -------- | -------- | ---------- | ------------------------| 46 | | backup_file_source | yes | '/etc/hosts' | string | The file to be backed up | 47 | | backup_file_dest_folder | yes | '/tmp/backups' | string | The folder where backups are stored | 48 | | backup_file_dest_suffix | no | '.bak' | string | The suffix to be appended to backup files | 49 | | backup_file_dest_dir_owner | no | current user id | string | The owner permission for back up folder | 50 | | backup_file_dest_dir_group | no | current group id | string | The group permission for the back up folder | 51 | | backup_file_dest_dir_mode | no | '0750' | string | The mode permission for the backup folder | 52 | | backup_file_dest_owner | no | current user id | string | The owner permission for the backed up file | 53 | | backup_file_dest_group | no | current group id | string | The group permission for the backed up file | 54 | | backup_file_dest_mode | no | '0640' | string | The mode permission for the backed up file | 55 | | backup_file_remote_source | no | true | bool | If the source file exists on the remote system | 56 | 57 | Dependencies 58 | ------------ 59 | 60 | No dependencies other than the collections included in the requirements.yml 61 | 62 | - kubernetes.core collection 63 | - community.okd or redhat.openshift collection 64 | - Required collections are included in the requirements.yml file that can be installed with `ansible-galaxy install -r requirements.yml` command 65 | 66 | Example Playbook 67 | ---------------- 68 | 69 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 70 | 71 | - name: Simple test case 72 | hosts: all 73 | connection: community.okd.oc 74 | vars: 75 | backup_file_source: '/etc/resolv.conf' 76 | backup_file_dest_folder: '/tmp/backups' 77 | roles: 78 | - backup_file 79 | 80 | License 81 | ------- 82 | 83 | GNU General Public License v3.0 or later 84 | -------------------------------------------------------------------------------- /devfile.yaml: -------------------------------------------------------------------------------- 1 | # cspell: disable=devspaces 2 | schemaVersion: 2.2.2 3 | metadata: 4 | name: ansible-demo 5 | components: 6 | - name: tooling-container 7 | container: 8 | image: ghcr.io/ansible/ansible-devspaces@sha256:a28fa23d254ff1b3ae10b95a0812132148f141bda4516661e40d0c49c4ace200 # v24.10.2 9 | memoryRequest: 256M 10 | memoryLimit: 6Gi 11 | cpuRequest: 250m 12 | cpuLimit: 2000m 13 | args: ['tail', '-f', '/dev/null'] 14 | env: 15 | - name: 'ANSIBLE_COLLECTIONS_PATH' 16 | value: '~/.ansible/collections:/usr/share/ansible/collections:/projects/ansible-devspaces-demo/collections' 17 | commands: 18 | 19 | - id: molecule-create 20 | exec: 21 | label: "1.Molecule: start a test pod for the automation" 22 | commandLine: 'source $HOME/.bashrc && molecule create' 23 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo/collections/ansible_collections/sample_namespace/sample_collection/extensions 24 | group: 25 | kind: run 26 | isDefault: true 27 | component: tooling-container 28 | 29 | - id: molecule-list 30 | exec: 31 | label: "2.Molecule: view the test instance that was created" 32 | commandLine: 'source $HOME/.bashrc && molecule list' 33 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo/collections/ansible_collections/sample_namespace/sample_collection/extensions 34 | group: 35 | kind: run 36 | isDefault: true 37 | component: tooling-container 38 | 39 | - id: molecule-converge 40 | exec: 41 | label: "3.Molecule: apply the role to the pod" 42 | commandLine: 'source $HOME/.bashrc && molecule converge' 43 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo/collections/ansible_collections/sample_namespace/sample_collection/extensions 44 | group: 45 | kind: run 46 | isDefault: true 47 | component: tooling-container 48 | 49 | - id: molecule-verify 50 | exec: 51 | label: "4.Molecule: run the verification against the test pod" 52 | commandLine: 'source $HOME/.bashrc && molecule verify' 53 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo/collections/ansible_collections/sample_namespace/sample_collection/extensions 54 | group: 55 | kind: run 56 | isDefault: true 57 | component: tooling-container 58 | 59 | - id: molecule-destroy 60 | exec: 61 | label: "5.Molecule: reset the test pod back to a fresh instance" 62 | commandLine: 'source $HOME/.bashrc && molecule destroy' 63 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo/collections/ansible_collections/sample_namespace/sample_collection/extensions 64 | group: 65 | kind: run 66 | isDefault: true 67 | component: tooling-container 68 | 69 | - id: molecule-test 70 | exec: 71 | label: "6.Molecule: run the full molecule test" 72 | commandLine: 'source $HOME/.bashrc && molecule test' 73 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo/collections/ansible_collections/sample_namespace/sample_collection/extensions 74 | group: 75 | kind: run 76 | isDefault: true 77 | component: tooling-container 78 | 79 | - id: ansible-navigator 80 | exec: 81 | label: "Ansible-Navigator: Start ansible-navigator" 82 | commandLine: | 83 | if [ ! -d "$HOME/.cache/ansible-navigator" ]; then 84 | mkdir -p "$HOME/.cache/ansible-navigator" 85 | fi 86 | cp /usr/local/lib/python3.11/site-packages/ansible_navigator/data/catalog_collections.py $HOME/.cache/ansible-navigator 87 | ansible-navigator --ee false 88 | workingDir: ${PROJECTS_ROOT}/ansible-devspaces-demo 89 | component: tooling-container 90 | events: 91 | preStop: 92 | - "molecule-destroy" 93 | -------------------------------------------------------------------------------- /collections/ansible_collections/sample_namespace/sample_collection/extensions/molecule/default/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | gather_facts: false 7 | connection: community.okd.oc 8 | # vars: 9 | # __backup_file_base: "{{ backup_file_source | basename }}" 10 | # __backup_file_base_suffix: "{{ backup_file_base }}{{ backup_file_dest_suffix }}" 11 | # __backup_file_destination_path: "{{ backup_file_dest_folder }}/{{ backup_file_dest_suffix }}" 12 | tasks: 13 | # TODO: change this to not be hard coded? 14 | - name: Verifier | include default role vars 15 | ansible.builtin.include_vars: 16 | dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/../roles/backup_file/defaults/" 17 | extensions: 18 | - 'yml' 19 | 20 | - name: Verifier | Check if the backup destination directory exists 21 | vars: 22 | fail_msg: "FAIL - backup destination directory doesn't exist" 23 | block: 24 | 25 | - name: Verifier Backup Created | Check if backup destination directory exists 26 | ansible.builtin.stat: 27 | path: "{{ backup_file_dest_folder }}" 28 | register: __backup_file_dest_dir_stat 29 | 30 | - name: Verifier Backup Created | Assert backup file directory exists 31 | ansible.builtin.assert: 32 | that: 33 | - __backup_file_dest_dir_stat is defined 34 | - __backup_file_dest_dir_stat.stat.exists 35 | - __backup_file_dest_dir_stat.stat.isdir 36 | rescue: 37 | 38 | - name: Verifier Backup Created | Store failure message 39 | ansible.builtin.set_fact: 40 | backup_file_verifier_fail: "{{ backup_file_verifier_fail | default([]) + [fail_msg] }}" 41 | 42 | - name: Verifier | Check if the backup destination directory is writable 43 | vars: 44 | fail_msg: "FAIL - backup destination directory isn't writable at" 45 | block: 46 | 47 | - name: Verifier Backup Created | Assert backup file directory is writable 48 | ansible.builtin.assert: 49 | that: 50 | - __backup_file_dest_dir_stat is defined 51 | - __backup_file_dest_dir_stat.stat.exists 52 | - __backup_file_dest_dir_stat.stat.isdir 53 | - __backup_file_dest_dir_stat.stat.writeable 54 | rescue: 55 | 56 | - name: Verifier Backup Created | Store failure message 57 | ansible.builtin.set_fact: 58 | backup_file_verifier_fail: "{{ backup_file_verifier_fail | default([]) + [fail_msg] }}" 59 | 60 | - name: Verifier | Check if the backup created 61 | vars: 62 | fail_msg: "FAIL - backup file doesn't exist or is a link" 63 | block: 64 | 65 | - name: Verifier Backup Created | Check if backup file was created 66 | ansible.builtin.stat: 67 | path: "{{ backup_file_dest_folder }}/{{ backup_file_source | basename }}{{ backup_file_dest_suffix }}" 68 | register: __backup_file_dest_stat 69 | 70 | - name: Verifier Backup Created | Assert backup file exists and isn't a link 71 | ansible.builtin.assert: 72 | that: 73 | - __backup_file_dest_stat is defined 74 | - __backup_file_dest_stat.stat.exists 75 | - not __backup_file_dest_stat.stat.islnk 76 | rescue: 77 | 78 | - name: Verifier Backup Created | Store failure message 79 | ansible.builtin.set_fact: 80 | backup_file_verifier_fail: "{{ backup_file_verifier_fail | default([]) + [fail_msg] }}" 81 | 82 | - name: Verifier | Check that backup matches source 83 | vars: 84 | fail_msg: "FAIL - backup file doesn't match source" 85 | block: 86 | 87 | - name: Verifier Backup Created | Fail immediately if backup file doesn't exist 88 | ansible.builtin.fail: 89 | when: 90 | - __backup_file_dest_stat is not defined 91 | - not __backup_file_dest_stat.stat.exists 92 | 93 | - name: Verifier Backup Created | Store information about source 94 | ansible.builtin.stat: 95 | path: "{{ backup_file_source }}" 96 | register: __backup_file_source_stat 97 | 98 | - name: Verifier Backup Created | Assert source and backup file have matching checksums 99 | ansible.builtin.assert: 100 | that: 101 | - __backup_file_dest_stat is defined 102 | - __backup_file_dest_stat.stat.checksum is defined 103 | - __backup_file_source_stat is defined 104 | - __backup_file_source_stat.stat.checksum is defined 105 | - __backup_file_source_stat.stat.checksum == __backup_file_source_stat.stat.checksum 106 | 107 | rescue: 108 | 109 | - name: Verifier Backup Created | Store failure message 110 | ansible.builtin.set_fact: 111 | backup_file_verifier_fail: "{{ backup_file_verifier_fail | default([]) + [fail_msg] }}" 112 | 113 | - name: Verifier | Fail if any tests failed 114 | when: 115 | - backup_file_verifier_fail is defined 116 | block: 117 | 118 | - name: Verifier | Show failures 119 | ansible.builtin.debug: 120 | msg: 121 | - "Role failed with the following messages" 122 | - "{{ backup_file_verifier_fail }}" 123 | 124 | - name: Verifier | Fail test 125 | ansible.builtin.fail: 126 | msg: "{{ backup_file_verifier_fail }}" 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Repository Archived 🚨 2 | 3 | This repository has been archived and is no longer actively maintained. 4 | 5 | It has been moved to [https://github.com/redhat-developer-demos/ansible-devspaces-demo](https://github.com/redhat-developer-demos/ansible-devspaces-demo/tree/devspaces-3-rhel-8). 6 | 7 | Please refer to the new repository for the latest updates and contributions. 8 | 9 | Thank you for your interest and support! 😊 10 | 11 | 12 | # Ansible Development on OpenShift Dev Spaces 13 | 14 | To get started, simply click the button below... 15 | 16 | [![Contribute](https://www.eclipse.org/che/contribute.svg)](https://workspaces.openshift.com/f?url=https://github.com/devspaces-samples/ansible-devspaces-demo) 17 | 18 | This repository provides a development environment for Ansible playbook creation, testing with Molecule, and ansible-lint checks using OpenShift Dev Spaces. 19 | 20 | ## Summary 21 | 22 | This repository contains a `devfile.yaml` file, which defines the development environment for Ansible. The DevSpace created using this `devfile` provides the necessary tools and dependencies for Ansible playbook development, testing with Molecule, and linting with ansible-lint. This is designed to be used in environments where developers do not have easy access to linux systems from which to develop ansible automation content, but do have OpenShift. 23 | 24 | The `devfile.yaml` includes configurations for: 25 | 26 | - Ansible 27 | - Molecule (testing framework for Ansible roles) 28 | - Ansible Lint (tool for checking best practices and potential issues in Ansible code) 29 | 30 | You can use the provided DevSpace to start working on your Ansible projects immediately, without worrying about setting up the development environment manually. 31 | 32 | ## Setting up OpenShift DevSpaces 33 | 34 | To get started with OpenShift Dev Spaces, refer to the [OpenShift Dev Spaces documentation](https://access.redhat.com/documentation/en-us/red_hat_openshift_dev_spaces/3.5/html/administration_guide/index) for detailed instructions on setting up your development environment and creating your DevSpaces. 35 | 36 | ## Base Image Of Devfile 37 | 38 | [Community Ansible Dev Spaces Image](https://github.com/ansible/community-ansible-devspaces-image) is used as an image for Ansible development and it's defined in the `devfile.yaml`. 39 | 40 | ### GitHub OAuth2 41 | 42 | The instructions for configuring OAuth2 for GitHub can be found at the following link: 43 | 44 | https://access.redhat.com/documentation/en-us/red_hat_openshift_dev_spaces/3.5/html/administration_guide/configuring-devspaces#configuring-oauth-2-for-github 45 | 46 | Once the secret is in place, restart the main Dev Space container. Any workspace created before this step is complete will NOT have access to GitHub OAuth, and will need to be deleted and recreated to get access. 47 | 48 | NOTE: You will still need to configured your name/email globally the first time your workspace is accessed (or once for each new workspace, if you choose not to configure globally). 49 | 50 | ``` 51 | git config --global user.name "Homer Simpson" 52 | git config --global user.email homer@springfieldpower.com 53 | ``` 54 | 55 | ## Sample Molecule Testing Role 56 | 57 | A sample role has been provided in the collections/ansible_collections/sample_namespace/sample_collection/roles/backup_file directory to experiment with Test Driven Development using Molecule and OpenShift DevSpaces. A molecule verifier has been configured to test that the role functions as expected. 58 | 59 | ### Automation requirements 60 | 1. Make a backup of a file identified using the backup_file_source variable 61 | 2. The backup should be stored in the directory identified by the backup_file_dest_folder variable 62 | 3. If the backup directory doesn't exist, it should be created and writable 63 | 4. The backup file should have a suffix appended such as '.bak' which is identified by the backup_file_dest_suffix variable 64 | 65 | ### To begin development against the backup_file role 66 | 1. Click the three horizontal bar icon in the top left of the window and select 'Terminal' -> 'New Terminal' 67 | 2. Click into the terminal window 68 | 3. Change directory into backup file role `cd collections/ansible_collections/sample_namespace/sample_collection/extensions/` 69 | 4. Run `molecule create`. This will start a test pod for the automation to run against (defined in roles/backup_file/molecule/default/molecule.yml). 70 | 5. Run `molecule list` and `oc get pods` to view the test instance that was created 71 | 6. Run `molecule verify` to run the verification against the test pod and see the failures to help guide the tasks necessary in the role. 72 | 7. Run `molecule converge` to apply the role to the pod. This will create a backup of a file in the backup destination folder with a suffix appended. 73 | 8. Run `molecule converge` to execute the role against the test instance, and `molecule verify` to see if any tests are still failing. Repeat this until all tests pass. 74 | 75 | To reset your test pod back to a fresh instance you can run `molecule destroy` and then `molecule create` to recreate it. To run the full molecule test without stepping through each stage, run `molecule test`. 76 | 77 | ## Contributing 78 | 79 | Contributions to this repository are welcome! If you find any issues or have suggestions for improvements, feel free to open an issue with [Red Hat](https://issues.redhat.com/projects/CRW/issues). 80 | 81 | ## Code of Conduct 82 | We ask all of our community members and contributors to adhere to the [Ansible code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html). If you have questions or need assistance, please reach out to our community team at [codeofconduct@ansible.com](mailto:codeofconduct@ansible.com) 83 | --------------------------------------------------------------------------------