Coder Social home page Coder Social logo

ansible-operator's Introduction

Ansible Operator: An Operator Backed by Ansible

Project Status: pre-alpha

The project is currently pre-alpha, and it is expected that breaking changes to the API will be made in the upcoming releases.

Example of how to use the Ansible Operator

Quickstart

To quickly get started you can use minikube to start a cluster. Then you can follow the below commands to deploy an operator, create an custom resource and have your deployed operator react to that resource.

$ kubectl create -f example/deploy/rbac.yaml
$ kubectl create -f example/deploy/crd.yaml
$ kubectl create -f example/deploy/operator.yaml

After you run these three commands you should have a running operator pod.

$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
ansible-operator-686fff7889-whfdf   1/1       Running   0          38s

Next, you should create a custom resource.

$ kubectl create -f deploy/cr.yaml

After this is created you should see a new pod.

$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
ansible-operator-686fff7889-whfdf   1/1       Running   0          2m
test-5b5d4b7cdf-2p9d9               1/1       Running   0          0s

You should also notice that the logs of the created resource contain a default message.

$ kubectl logs -f test-5b5d4b7cdf-2p9d9
hello world
hello world
hello world

To change this message you can edit the custom resource by running $ kubectl edit database example, and add message to the spec. This should cause a new pod to run.

$ kubectl get pods
NAME                                READY     STATUS        RESTARTS   AGE
ansible-operator-686fff7889-whfdf   1/1       Running       0          6m
test-5b5d4b7cdf-2p9d9               1/1       Terminating   0          4m
test-88b77fc65-sjjf5                1/1       Running       0          22s

And you should be able to see the new log message.

$ kubectl logs -f test-88b77fc65-sjjf5
new log message!
new log message!
new log message!

Run Ansible Operator locally

For development, it can be convenient to run the operator locally instead of in the cluster.

mkdir -p /opt/anisble/roles
cp example/watches.yaml /opt/ansible/
cp example/playbook.yaml /opt/anisble/
cp -a example/busybox /opt/ansible/roles/

Ensure that ansible, ansible-runner (>= 1.1.0), and ansible-runner-http are installed. Consider using a python virtualenv. If you run the operator in a shell with an active virtualenv, that will be propagated to ansible-runner and ansible.

Run

To run this operator locally, you can do the following:

  1. Start a kubernetes cluster, possibly with minikube
  2. kubectl create -f deploy/crd.yaml
  3. operator-sdk up local
  4. kubectl create -f deploy/cr.yaml

You should then see the operator creating resources in response to the CR's creation.

More Detailed Explanation

Extra vars sent to Ansible

The extravars that are sent to ansible are predefined and managed by the operator.

For the CR example:

apiVersion: "app.example.com/v1alpha1"
kind: "Database"
metadata:
  name: "example"
spec:
  message:"Hello world 2"
  newParameter: "newParam"

The structure is:

{ "meta": {
        "name": "<cr-name>",
        "namespace": "<cr-namespace>",
  },
  "message": "Hello world 2",
  "new_parameter": "newParam",
  "_app_example_com_database": {
     <Full CRD>
   },
}

Ansible Operator Base Image

It is an CentOS based ansible-runner image, with the operator installed.

This image should be used as a base image. An example of this can be found here

The Operator expects a mapping file, which lists each GVK to watch and the corresponding path to an ansible role or playbook, to be copied into the container at a predefined location: /opt/ansible/watches.yaml

Example:

COPY watches.yaml /opt/ansible/watches.yaml

The Watches file format is yaml and is an array of objects. The object has mandatory fields:

version: The version of the Custom Resource that you will be watching.

group: The group of the Custom Resource that you will be watching.

kind: The kind of the Custom Resource that you will be watching.

playbook: This is the path to the playbook that you have added to the container. This playbook is expected to be simply a way to call roles. This field is mutually exclusive with the "role" field.

role: This is the path to the role that you have added to the container. For example if your roles directory is at /opt/ansible/roles/ and your role is named busybox, this value will be /opt/ansible/roles/busybox. This field is mutually exclusive with the "playbook" field.

Example specifying a playbook:

---
- version: v1alpha1
  group: app.example.com
  kind: Database
  playbook: /opt/ansible/playbook.yaml

Example specifying a role:

---
- version: v1alpha1
  group: app.example.com
  kind: Database
  role: /opt/ansible/roles/busybox/

The operator expects that the ansible

  • can handle extra vars to take parameters from the spec of the CRD
  • that it is idempotent
  • should be expected to be called often and without changes

Deploying your new Ansible Operator.

To deploy your ansible operator you will need to do 3 things.

  1. Setup the RBAC permissions for the service account that the operator will run as.
  2. Deploy the CRD into the cluster.
  3. Deploy the operator deployment into the cluster.
RBAC Permissions

RBAC is the way to define permissions for a user/service account in kubernetes. The permissions in the example do two different things; create a Role and create a Role Binding. In this example we grant access to many of the “core” resources (pods,secrets,services) as well as the apps resources (deployments…). The third thing this role grants access to is the group: “app.example.com”. This is where you should state your group that you are using for the CRD. Here is the example that will help you run the operator in minikube.

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: app-operator
rules:
- apiGroups:
  - app.example.com
  resources:
  - "*"
  verbs:
  - "*"
- apiGroups:
  - ""
  resources:
  - pods
  - services
  - endpoints
  - persistentvolumeclaims
  - events
  - configmaps
  - secrets
  verbs:
  - "*"
- apiGroups:
  - apps
  resources:
  - deployments
  - daemonsets
  - replicasets
  - statefulsets
  verbs:
  - "*"
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: default-account-app-operator
subjects:
- kind: ServiceAccount
  name: default
roleRef:
  kind: Role
  name: app-operator
  apiGroup: rbac.authorization.k8s.io
Install the CRD into the Cluster

The CRD or Custom Resource Definition is a key extension point in kubernetes. Here you define a new resource type, and Kubernetes will handle saving and persisting this resource definition. Here is some documentation on CRDs: https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/ An example below will work with the busybox role and rbac roles above.

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: databases.app.example.com
spec:
  group: app.example.com
  names:
    kind: Database
    listKind: DatabaseList
    plural: databases
    singular: database
  scope: Namespaced
  version: v1alpha1

Some things to note are that CRDs have two sections, the Spec section and the Status section. The Spec is used by the user creating the CR (custom resource). This is where a user should define the parameters for the role. The Status field is used by the operator to handle the “state” of the resource. This should not be touched by the user. There are two other fields on a CR the ObjectMeta and TypeMeta which all kubernetes objects share.

Operator Deployment

To deploy the operator, you should create this to manage the operator pod. The below deployment with the above code should start a running operator! Backed by Ansible!

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ansible-operator
spec:
  replicas: 1
  selector:
    matchLabels:
      name: ansible-operator
  template:
    metadata:
      labels:
        name: ansible-operator
    spec:
      containers:
        - name: ansible-operator
          image: quay.io/water-hole/busybox-ansible-operator
          command:
          - ansible-operator
          imagePullPolicy: Always
          env:
            - name: WATCH_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace


To create a Custom Resource here is an example:
apiVersion: "app.example.com/v1alpha1"
kind: "Database"
metadata:
  name: "example"
spec:
  message: hello world 2

ansible-operator's People

Contributors

dymurray avatar ehelms avatar fabianvf avatar jimi-c avatar jmontleon avatar joelanford avatar mhrivnak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ansible-operator's Issues

Latest Build is Broken

Image Digest 2a6df59805b8 is broken.

Anything I'm trying to deploy using my operator build on top of 2a6df59805b8 ends up in:
{"level":"error","ts":1545062584.6350603,"logger":"kubebuilder.controller","msg":"Reconciler error","controller":"blueocean-controller","request":"kube-system/example-blueocean","error":"the server could not find the requested resource","stacktrace":"github.com/water-hole/ansible-operator/vendor/github.com/go-logr/zapr.(*zapLogger).Error\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:215\ngithub.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:158\ngithub.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:133\ngithub.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:134\ngithub.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait.Until\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}

Document how to add additional modules/dependencies for Ansible to operator's image.

We want to ensure that our developer documentation walks through a scenario of how to:

Add an experimental Ansible Module to the image
Add a python dependency (perhaps python-boto or similar)

This is intended to show a developer the changes they need to make to their Dockerfile, locations of where to copy files, update python libraries, etc.

improvements to config file

These improvements to /opt/ansible/config.yaml were suggested in a meeting this week. Here is how the format currently looks:

- name: Database
  version: v1alpha1
  group: app.example.com
  kind: Database
  path: /opt/ansible/roles/busybox/playbook.yaml

path currently only can reference a playbook. Since we want to support running either a playbook or a role directly, the path key will be replaced by playbook and role keys. They will be mutually exclusive.

The name key was deemed to not be valuable, so it should be removed.

Reconcile running all the time

The reconcile loop runs all the time. I would expect it to be executed only when change to CR is detected or when the reconcile timeout expires.

{"level":"info","ts":1545402668.8160658,"logger":"logging_event_handler","msg":"[playbook task]","name":"example-kubevirtssp","namespace":"myproject","gvk":"kubevirt.io/v1, Kind=KubevirtSsp","event_type":"playbook_on_task_start","job":"8954784443427127217","EventData.Name":"KubevirtSsp : Install VM templates"}
{"level":"info","ts":1545402690.185443,"logger":"runner","msg":"ansible-runner exited successfully","job":"8954784443427127217","name":"example-kubevirtssp","namespace":"myproject"}
{"level":"info","ts":1545402691.5898943,"logger":"logging_event_handler","msg":"[playbook task]","name":"example-kubevirtssp","namespace":"myproject","gvk":"kubevirt.io/v1, Kind=KubevirtSsp","event_type":"playbook_on_task_start","job":"1926785059355643186","EventData.Name":"KubevirtSsp : Install VM templates"}
{"level":"info","ts":1545402713.3503788,"logger":"runner","msg":"ansible-runner exited successfully","job":"1926785059355643186","name":"example-kubevirtssp","namespace":"myproject"}
{"level":"info","ts":1545402714.9376333,"logger":"logging_event_handler","msg":"[playbook task]","name":"example-kubevirtssp","namespace":"myproject","gvk":"kubevirt.io/v1, Kind=KubevirtSsp","event_type":"playbook_on_task_start","job":"5524602647031961978","EventData.Name":"KubevirtSsp : Install VM templates"}

The source code of my minimal operator is available here: https://github.com/MarSik/kubevirt-ssp-operator/tree/7a38a06d2ab4f317d2988552719cc4b9567f7c2e

I am running it on the following environment:

oc v3.11.16
kubernetes v1.11.0+d4cacc0
minishift v1.28.0+48e89ed
operator-sdk version v0.3.0+git

Stacktrace resource is missing

Attempt to install gogs using Ansible Operator resulted in this error,

{"level":"error","ts":1548832941.763671,"logger":"kubebuilder.controller","msg":"Reconciler error","controller":"gogs-controller","request":"ocpadv-gogs-operator/gogs-server","error":"the server could not find the requested resource","stacktrace":"github.com/water-hole/ansible-operator/vendor/github.com/go-logr/zapr.(*zapLogger).Error\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:215\ngithub.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:158\ngithub.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:133\ngithub.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:134\ngithub.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait.Until\n\t/home/travis/gopath/src/github.com/water-hole/ansible-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}

rename config.yaml

The operator's config.yaml file is not a config file in the usual sense. It maps GVK to an ansible role or playbook. We would never put other runtime settings in it such as debug level, what port to run the proxy on, etc. This file is how you compose an operator, and changing its contents could leave you with a fundamentally different operator.

As such, I propose changing the name to avoid confusion. Since the file is a list of GVKs to watch, combined with info about what to do for that GVK, I suggest renaming it to watches.yaml.

ansible event log output is hard to use

After #42, log output consists of a ton a JSON, which is the raw representation of ansible events. It would be more useful to pull out the valuable pieces and log them in a human-readable way.

Here's an example log statement. I think it's actually getting truncated.

INFO[0002] event: map[string]interface {}{"play":"localhost", "task_uuid":"d46d6db6-cb69-5e0a-71b5-000000000010", "playbook_uuid":"901c3b53-9691-425f-a6d4-80d149fd97ec", "pid":29311, "event_loop":interface {}(nil), "play_pattern":"localhost", "task":"Gathering Facts", "task_args":"_ansible_version=2.6.2, _ansible_selinux_special_fs=['fuse', 'nfs', 'vboxsf', 'ramfs', '9p'], _ansible_no_log=False, gather_timeout=10, _ansible_module_name=setup, _ansible_debug=False, _ansible_verbosity=0, _ansible_keep_remote_files=False, _ansible_syslog_facility=LOG_USER, _ansible_socket=None, gather_subset=all, _ansible_diff=False, _ansible_remote_tmp=~/.ansible/tmp, _ansible_shell_executable=/bin/sh, _ansible_check_mode=False, _ansible_tmpdir=/home/mhrivnak/.ansible/tmp/ansible-tmp-1536350800.09-121600817079545/", "play_uuid":"d46d6db6-cb69-5e0a-71b5-000000000006", "playbook":"/tmp/ansible-operator/runner/app.example.com/v1alpha1/Database/default/example/project/5756a9dc540842bb9be6b5d5af691060", "remote_addr":"localhost", "res":map[string]interface {}{"invocation":map[string]interface {}{"module_args":map[string]interface {}{"filter":"*", "gather_subset":[]interface {}{"all"}, "fact_path":"/etc/ansible/facts.d", "gather_timeout":10}}, "ansible_facts":map[string]interface {}{"ansible_userspace_architecture":"x86_64", "ansible_iscsi_iqn":"iqn.1994-05.com.redhat:71fc25b8ad3", "ansible_virbr0":map[string]interface {}{"features":map[string]interface {}{"rx_vlan_offload":"off [fixed]", "highdma":"off [requested on]", "esp_hw_offload":"off [fixed]", "tx_checksum_fcoe_crc":"off [fixed]", "rx_vlan_filter":"off [fixed]", "scatter_gather":"on", "tx_sctp_segmentation":"off [requested on]", "tx_gre_segmentation":"on", "tx_gso_partial":"on", "rx_gro_hw":"off [fixed]", "tx_tcp_mangleid_segmentation":"on", "fcoe_mtu":"off [fixed]", "tx_nocache_copy":"off", "receive_hashing":"off [fixed]", "generic_segmentation_offload":"on", "tx_scatter_gather_fraglist":"on", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_scatter_gather":"on", "netns_local":"on [fixed]", "ntuple_filters":"off [fixed]", "tx_fcoe_segmentation":"off [requested on]", "tx_udp_tnl_csum_segmentation":"on", "rx_fcs":"off [fixed]", "tx_vlan_stag_hw_insert":"on", "tx_esp_segmentation":"on", "tx_vlan_offload":"on", "tx_checksum_ipv6":"off [fixed]", "tx_ipxip6_segmentation":"on", "rx_checksumming":"off [fixed]", "tcp_segmentation_offload":"on", "generic_receive_offload":"on", "rx_all":"off [fixed]", "vlan_challenged":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "large_receive_offload":"off [fixed]", "tx_ipxip4_segmentation":"on", "tx_udp_tnl_segmentation":"on", "tx_tcp6_segmentation":"on", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_gre_csum_segmentation":"on", "tx_checksum_ipv4":"off [fixed]", "udp_fragmentation_offload":"off", "tls_hw_record":"off [fixed]", "tx_gso_robust":"off [requested on]", "esp_tx_csum_hw_offload":"off [fixed]", "hw_tc_offload":"off [fixed]", "tx_lockless":"on [fixed]", "tx_checksumming":"on", "loopback":"off [fixed]", "tx_tcp_segmentation":"on", "tx_checksum_ip_generic":"on", "tx_tcp_ecn_segmentation":"on", "rx_vlan_stag_filter":"off [fixed]", "l2_fwd_offload":"off [fixed]"}, "mtu":1500, "device":"virbr0", "stp":true, "ipv4":map[string]interface {}{"broadcast":"192.168.122.255", "netmask":"255.255.255.0", "network":"192.168.122.0", "address":"192.168.122.1"}, "type":"bridge", "hw_timestamp_filters":[]interface {}{}, "macaddress":"52:54:00:31:a1:44", "interfaces":[]interface {}{"virbr0-nic", "vnet0"}, "id":"8000.52540031a144", "promisc":false, "active":true, "timestamping":[]interface {}{"rx_software", "software"}}, "ansible_virbr2":map[string]interface {}{"device":"virbr2", "promisc":false, "timestamping":[]interface {}{"rx_software", "software"}, "type":"bridge", "features":map[string]interface {}{"rx_fcs":"off [fixed]", "tx_tcp_mangleid_segmentation":"on", "fcoe_mtu":"off [fixed]", "l2_fwd_offload":"off [fixed]", "tx_ipxip4_segmentation":"on", "loopback":"off [fixed]", "rx_gro_hw":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_gre_segmentation":"on", "tx_vlan_offload":"on", "generic_receive_offload":"on", "esp_hw_offload":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "large_receive_offload":"off [fixed]", "tx_gso_robust":"off [requested on]", "tx_checksum_sctp":"off [fixed]", "tx_tcp_segmentation":"on", "tx_checksum_ipv4":"off [fixed]", "tx_ipxip6_segmentation":"on", "tx_checksum_fcoe_crc":"off [fixed]", "tx_checksumming":"on", "rx_checksumming":"off [fixed]", "tx_udp_tnl_segmentation":"on", "udp_fragmentation_offload":"off", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_esp_segmentation":"on", "esp_tx_csum_hw_offload":"off [fixed]", "tx_gso_partial":"on", "tx_nocache_copy":"off", "tx_tcp6_segmentation":"on", "rx_vlan_filter":"off [fixed]", "tx_tcp_ecn_segmentation":"on", "netns_local":"on [fixed]", "tx_checksum_ip_generic":"on", "vlan_challenged":"off [fixed]", "tx_sctp_segmentation":"off [requested on]", "rx_vlan_offload":"off [fixed]", "tx_gre_csum_segmentation":"on", "tx_scatter_gather_fraglist":"on", "rx_all":"off [fixed]", "scatter_gather":"on", "tx_fcoe_segmentation":"off [requested on]", "tx_checksum_ipv6":"off [fixed]", "tx_udp_tnl_csum_segmentation":"on", "tx_scatter_gather":"on", "generic_segmentation_offload":"on", "tls_hw_record":"off [fixed]", "hw_tc_offload":"off [fixed]", "receive_hashing":"off [fixed]", "highdma":"off [requested on]", "tx_lockless":"on [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_vlan_stag_hw_insert":"on", "tcp_segmentation_offload":"on"}, "interfaces":[]interface {}{"virbr2-nic", "vnet1"}, "id":"8000.525400a23841", "mtu":1500, "hw_timestamp_filters":[]interface {}{}, "macaddress":"52:54:00:a2:38:41", "stp":true, "ipv4":map[string]interface {}{"broadcast":"192.168.39.255", "netmask":"255.255.255.0", "network":"192.168.39.0", "address":"192.168.39.1"}, "active":true}, "ansible_uptime_seconds":2.077795e+06, "ansible_form_factor":"Notebook", "ansible_processor":[]interface {}{"0", "GenuineIntel", "Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz", "1", "GenuineIntel", "Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz", "2", "GenuineIntel", "Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz", "3", "GenuineIntel", "Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz"}, "ansible_mounts":[]interface {}{map[string]interface {}{"block_used":1.8625832e+07, "size_total":1.05152176128e+11, "block_total":2.5671918e+07, "size_available":2.8860768256e+10, "inode_total":6.5536e+06, "block_size":4096, "mount":"/", "fstype":"ext4", "device":"/dev/mapper/fedora-root", "inode_available":5.808222e+06, "uuid":"2ce59711-ff80-4fd9-9868-3ed436a5dd9f", "block_available":7.046086e+06, "options":"rw,seclabel,relatime", "inode_used":745378}, map[string]interface {}{"block_total":249830, "device":"/dev/nvme0n1p2", "uuid":"072819ba-8d1e-4dfe-872d-96e302d53461", "block_size":4096, "block_used":66275, "size_available":7.5184128e+08, "fstype":"ext4", "inode_total":65536, "inode_used":103, "inode_available":65433, "size_total":1.02330368e+09, "block_available":183555, "options":"rw,seclabel,relatime", "mount":"/boot"}, map[string]interface {}{"inode_total":0, "device":"/dev/nvme0n1p1", "inode_used":0, "block_used":4520, "uuid":"4B09-5C93", "block_total":51145, "mount":"/boot/efi", "options":"rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=ascii,shortname=winnt,errors=remount-ro", "block_size":4096, "inode_available":0, "size_total":2.0948992e+08, "block_available":46625, "size_available":1.90976e+08, "fstype":"vfat"}, map[string]interface {}{"uuid":"c613d87a-8f23-4d1b-9402-0a33d3e16ba6", "block_total":1.283596e+07, "size_available":1.242243072e+09, "options":"rw,seclabel,relatime", "device":"/dev/mapper/fedora-home", "mount":"/home", "inode_total":3.2768e+06, "inode_used":669204, "block_size":4096, "block_used":1.2532678e+07, "size_total":5.257609216e+10, "fstype":"ext4", "block_available":303282, "inode_available":2.607596e+06}, map[string]interface {}{"uuid":"2ce59711-ff80-4fd9-9868-3ed436a5dd9f", "mount":"/var/lib/docker/containers", "inode_total":6.5536e+06, "options":"rw,seclabel,relatime,bind", "inode_used":745378, "size_total":1.05152176128e+11, "block_total":2.5671918e+07, "size_available":2.8860768256e+10, "inode_available":5.808222e+06, "block_used":1.8625832e+07, "block_size":4096, "block_available":7.046086e+06, "fstype":"ext4", "device":"/dev/mapper/fedora-root"}, map[string]interface {}{"uuid":"2ce59711-ff80-4fd9-9868-3ed436a5dd9f", "block_available":7.046086e+06, "block_total":2.5671918e+07, "mount":"/var/lib/docker/overlay2", "device":"/dev/mapper/fedora-root", "inode_available":5.808222e+06, "inode_total":6.5536e+06, "options":"rw,seclabel,relatime,bind", "inode_used":745378, "block_size":4096, "block_used":1.8625832e+07, "size_total":1.05152176128e+11, "size_available":2.8860768256e+10, "fstype":"ext4"}}, "ansible_real_group_id":1000, "ansible_dns":map[string]interface {}{"nameservers":[]interface {}{"10.192.206.245", "10.192.20.245", "10.200.0.246"}, "search":[]interface {}{"redhat.com"}}, "ansible_nodename":"localhost.localdomain", "ansible_domain":"localdomain", "ansible_date_time":map[string]interface {}{"tz_offset":"-0400", "month":"09", "second":"40", "weekday_number":"5", "year":"2018", "iso8601_micro":"2018-09-07T20:06:40.522315Z", "hour":"16", "minute":"06", "date":"2018-09-07", "iso8601":"2018-09-07T20:06:40Z", "iso8601_basic":"20180907T160640522212", "tz":"EDT", "weeknumber":"36", "weekday":"Friday", "time":"16:06:40", "day":"07", "iso8601_basic_short":"20180907T160640", "epoch":"1536350800"}, "ansible_distribution_file_variety":"RedHat", "ansible_architecture":"x86_64", "ansible_cmdline":map[string]interface {}{"root":"/dev/mapper/fedora-root", "LANG":"en_US.UTF-8", "BOOT_IMAGE":"/vmlinuz-4.17.12-200.fc28.x86_64", "quiet":true, "rhgb":true, "rd.lvm.lv":"fedora/swap", "rd.luks.uuid":"luks-859ee22d-0209-4fa7-b097-2af931856cde", "ro":true}, "ansible_system_capabilities_enforced":"True", "ansible_product_serial":"NA", "ansible_fips":false, "ansible_processor_threads_per_core":2, "ansible_service_mgr":"systemd", "ansible_memfree_mb":852, "ansible_hostname":"localhost", "ansible_default_ipv4":map[string]interface {}{"address":"10.192.217.118", "interface":"wlp58s0", "network":"10.192.216.0", "broadcast":"10.192.219.255", "alias":"wlp58s0", "netmask":"255.255.252.0", "type":"ether", "gateway":"10.192.219.254", "macaddress":"d4:6d:6d:b6:cb:69", "mtu":1500}, "ansible_kernel":"4.17.12-200.fc28.x86_64", "ansible_bios_version":"N1WET44W (1.23 )", "ansible_selinux":map[string]interface {}{"status":"Missing selinux Python library"}, "ansible_virbr1":map[string]interface {}{"ipv4":map[string]interface {}{"broadcast":"192.168.42.255", "netmask":"255.255.255.0", "network":"192.168.42.0", "address":"192.168.42.1"}, "timestamping":[]interface {}{"rx_software", "software"}, "macaddress":"52:54:00:01:93:e9", "promisc":false, "id":"8000.5254000193e9", "mtu":1500, "device":"virbr1", "stp":true, "active":false, "type":"bridge", "features":map[string]interface {}{"rx_fcs":"off [fixed]", "loopback":"off [fixed]", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_gso_partial":"on", "tx_tcp_segmentation":"on", "netns_local":"on [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "highdma":"off [requested on]", "tx_gso_robust":"off [requested on]", "scatter_gather":"on", "tx_vlan_stag_hw_insert":"on", "tx_checksum_fcoe_crc":"off [fixed]", "tx_nocache_copy":"off", "tx_checksum_ipv4":"off [fixed]", "generic_segmentation_offload":"on", "hw_tc_offload":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "tx_scatter_gather":"on", "l2_fwd_offload":"off [fixed]", "receive_hashing":"off [fixed]", "tx_gre_segmentation":"on", "generic_receive_offload":"on", "tx_checksum_ipv6":"off [fixed]", "rx_all":"off [fixed]", "tx_tcp_mangleid_segmentation":"on", "vlan_challenged":"off [fixed]", "fcoe_mtu":"off [fixed]", "rx_vlan_offload":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_sctp_segmentation":"off [requested on]", "tx_tcp_ecn_segmentation":"on", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_ipxip6_segmentation":"on", "tx_udp_tnl_segmentation":"on", "tls_hw_record":"off [fixed]", "tx_fcoe_segmentation":"off [requested on]", "tx_gre_csum_segmentation":"on", "tx_udp_tnl_csum_segmentation":"on", "rx_vlan_filter":"off [fixed]", "udp_fragmentation_offload":"off", "esp_hw_offload":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "rx_gro_hw":"off [fixed]", "tx_tcp6_segmentation":"on", "tx_checksum_ip_generic":"on", "tx_scatter_gather_fraglist":"on", "tx_ipxip4_segmentation":"on", "large_receive_offload":"off [fixed]", "tx_esp_segmentation":"on", "tcp_segmentation_offload":"on", "tx_vlan_offload":"on", "rx_checksumming":"off [fixed]", "tx_lockless":"on [fixed]", "tx_checksumming":"on"}, "interfaces":[]interface {}{"virbr1-nic"}, "hw_timestamp_filters":[]interface {}{}}, "ansible_is_chroot":false, "ansible_user_shell":"/bin/bash", "ansible_local":map[string]interface {}{}, "ansible_virtualization_role":"host", "ansible_effective_group_id":1000, "ansible_virbr0_nic":map[string]interface {}{"features":map[string]interface {}{"tx_checksum_sctp":"off [fixed]", "ntuple_filters":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "udp_fragmentation_offload":"off", "tx_ipxip4_segmentation":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]", "tx_tcp6_segmentation":"off [requested on]", "tx_sctp_segmentation":"off [fixed]", "tx_vlan_offload":"on", "tx_tcp_mangleid_segmentation":"off", "tx_tcp_segmentation":"off [requested on]", "loopback":"off [fixed]", "tx_udp_tnl_segmentation":"off [fixed]", "rx_vlan_offload":"off [fixed]", "tx_nocache_copy":"off", "rx_fcs":"off [fixed]", "generic_receive_offload":"on", "tx_gso_partial":"off [fixed]", "tx_lockless":"on [fixed]", "rx_checksumming":"off [fixed]", "hw_tc_offload":"off [fixed]", "fcoe_mtu":"off [fixed]", "scatter_gather":"on", "highdma":"off [fixed]", "generic_segmentation_offload":"on", "receive_hashing":"off [fixed]", "tx_tcp_ecn_segmentation":"off [requested on]", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_vlan_stag_hw_insert":"on", "tx_gre_segmentation":"off [fixed]", "tx_checksum_ipv6":"off [fixed]", "vlan_challenged":"off [fixed]", "large_receive_offload":"off [fixed]", "tx_scatter_gather":"on", "tls_hw_record":"off [fixed]", "esp_hw_offload":"off [fixed]", "tx_gso_robust":"off [fixed]", "tx_checksum_ip_generic":"off [requested on]", "tx_fcoe_segmentation":"off [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_ipxip6_segmentation":"off [fixed]", "rx_gro_hw":"off [fixed]", "netns_local":"off [fixed]", "tx_gre_csum_segmentation":"off [fixed]", "tx_scatter_gather_fraglist":"on", "tx_checksum_fcoe_crc":"off [fixed]", "rx_vlan_filter":"off [fixed]", "tx_checksumming":"off", "tx_checksum_ipv4":"off [fixed]", "rx_all":"off [fixed]", "tcp_segmentation_offload":"off", "l2_fwd_offload":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "tx_esp_segmentation":"off [fixed]"}, "hw_timestamp_filters":[]interface {}{}, "device":"virbr0-nic", "promisc":true, "macaddress":"52:54:00:31:a1:44", "timestamping":[]interface {}{"tx_software", "rx_software", "software"}, "active":false, "type":"ether", "mtu":1500}, "ansible_default_ipv6":map[string]interface {}{}, "ansible_product_uuid":"NA", "ansible_all_ipv6_addresses":[]interface {}{"fe80::42:e9ff:febd:c91f", "fe80::fcaa:a4ff:feda:245c", "fe80::1090:23ec:9c5e:a5a7", "fe80::fcaa:a4ff:feda:245c"}, "ansible_swaptotal_mb":2047, "ansible_python_version":"2.7.15", "ansible_product_version":"ThinkPad T470s", "ansible_memory_mb":map[string]interface {}{"real":map[string]interface {}{"total":15919, "used":15067, "free":852}, "swap":map[string]interface {}{"cached":60, "total":2047, "free":1463, "used":584}, "nocache":map[string]interface {}{"used":11652, "free":4267}}, "ansible_apparmor":map[string]interface {}{"status":"disabled"}, "ansible_distribution_file_path":"/etc/redhat-release", "ansible_userspace_bits":"64", "ansible_distribution":"Fedora", "ansible_ssh_host_key_rsa_public":"AAAAB3NzaC1yc2EAAAADAQABAAABAQCvViwTKldJuCciWW50fBoFrUi4hsBF/YcN5z+x74FUoIEKvfiKYq8XdpBnzVWlVDjMvJqfXNRXsHyf79vEKZjkEFbaKz3AFkr/4dJb+4SV1Wesnjx8uV+Jd1KNEFlWhgZ/TvbgFYPImvebt0g2vGc8uRMJ4YKCF1B5YphjVuhGxr8LXXoGixQRSwSmDz0QCzvcla0ECzEWrb9TGnoN8y8rSKgtY/Wr7tkkNiPZ9RidFpObsZO39KjRF8j6Z71y0DDsh2e7MDfy/4sGVG+NikbR7Lluusf5iUkSETVWt7XIUeEYjEQVBzx6Awe7xrevYKpbUCOboM8m0rwWVbl8zSpz", "ansible_user_dir":"/home/mhrivnak", "ansible_memtotal_mb":15919, "ansible_interfaces":[]interface {}{"docker0", "lo", "wlp58s0", "enp0s31f6", "vnet0", "vnet1", "virbr1", "virbr1-nic", "virbr2-nic", "virbr2", "virbr0-nic", "virbr0"}, "ansible_product_name":"20HGS22D00", "ansible_vnet0":map[string]interface {}{"hw_timestamp_filters":[]interface {}{}, "device":"vnet0", "promisc":true, "timestamping":[]interface {}{"tx_software", "rx_software", "software"}, "ipv6":[]interface {}{map[string]interface {}{"scope":"link", "prefix":"64", "address":"fe80::fcaa:a4ff:feda:245c"}}, "active":true, "macaddress":"fe:aa:a4:da:24:5c", "features":map[string]interface {}{"tx_vlan_stag_hw_insert":"on", "tx_gso_partial":"off [fixed]", "rx_all":"off [fixed]", "rx_fcs":"off [fixed]", "loopback":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "tx_esp_segmentation":"off [fixed]", "l2_fwd_offload":"off [fixed]", "rx_gro_hw":"off [fixed]", "netns_local":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_vlan_offload":"on", "generic_receive_offload":"on", "tx_ipxip6_segmentation":"off [fixed]", "hw_tc_offload":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "rx_checksumming":"off [fixed]", "tx_sctp_segmentation":"off [fixed]", "tx_nocache_copy":"off", "receive_hashing":"off [fixed]", "tx_scatter_gather_fraglist":"on", "tx_tcp6_segmentation":"on", "tx_checksum_fcoe_crc":"off [fixed]", "udp_fragmentation_offload":"off", "tx_tcp_ecn_segmentation":"on", "tx_scatter_gather":"on", "tx_gre_csum_segmentation":"off [fixed]", "tx_lockless":"on [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "scatter_gather":"on", "esp_hw_offload":"off [fixed]", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_tcp_segmentation":"on", "tcp_segmentation_offload":"on", "tls_hw_record":"off [fixed]", "tx_fcoe_segmentation":"off [fixed]", "tx_tcp_mangleid_segmentation":"off", "tx_checksumming":"on", "rx_vlan_offload":"off [fixed]", "highdma":"off [fixed]", "tx_gso_robust":"off [fixed]", "fcoe_mtu":"off [fixed]", "rx_vlan_filter":"off [fixed]", "tx_checksum_ipv6":"off [fixed]", "large_receive_offload":"off [fixed]", "generic_segmentation_offload":"on", "tx_udp_tnl_segmentation":"off [fixed]", "tx_checksum_ip_generic":"on", "tx_gre_segmentation":"off [fixed]", "tx_ipxip4_segmentation":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "vlan_challenged":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]"}, "type":"ether", "mtu":1500, "speed":10}, "ansible_wlp58s0":map[string]interface {}{"ipv4":map[string]interface {}{"network":"10.192.216.0", "address":"10.192.217.118", "broadcast":"10.192.219.255", "netmask":"255.255.252.0"}, "type":"ether", "features":map[string]interface {}{"tx_ipxip4_segmentation":"off [fixed]", "fcoe_mtu":"off [fixed]", "tx_vlan_stag_hw_insert":"off [fixed]", "tx_esp_segmentation":"off [fixed]", "highdma":"on [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "rx_gro_hw":"off [fixed]", "tx_lockless":"off [fixed]", "tx_tcp_ecn_segmentation":"off [fixed]", "netns_local":"on [fixed]", "vlan_challenged":"off [fixed]", "tx_ipxip6_segmentation":"off [fixed]", "tx_gso_partial":"off [fixed]", "tx_udp_tnl_segmentation":"off [fixed]", "rx_vlan_offload":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_checksum_ip_generic":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_gre_segmentation":"off [fixed]", "tx_scatter_gather":"on [fixed]", "tx_gso_robust":"off [fixed]", "loopback":"off [fixed]", "rx_fcs":"off [fixed]", "scatter_gather":"on", "large_receive_offload":"off [fixed]", "generic_segmentation_offload":"on", "tx_vlan_offload":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "tx_checksum_ipv6":"off [fixed]", "tx_checksumming":"off", "rx_vlan_stag_filter":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "tx_checksum_fcoe_crc":"off [fixed]", "tx_fcoe_segmentation":"off [fixed]", "receive_hashing":"off [fixed]", "tls_hw_record":"off [fixed]", "hw_tc_offload":"off [fixed]", "tx_nocache_copy":"off", "rx_vlan_filter":"off [fixed]", "esp_hw_offload":"off [fixed]", "l2_fwd_offload":"off [fixed]", "tx_tcp6_segmentation":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]", "generic_receive_offload":"on", "tx_scatter_gather_fraglist":"off [fixed]", "tx_tcp_segmentation":"off [fixed]", "tcp_segmentation_offload":"off", "rx_all":"off [fixed]", "tx_tcp_mangleid_segmentation":"off [fixed]", "tx_gre_csum_segmentation":"off [fixed]", "udp_fragmentation_offload":"off", "rx_checksumming":"off [fixed]", "tx_sctp_segmentation":"off [fixed]"}, "pciid":"0000:3a:00.0", "module":"iwlwifi", "mtu":1500, "promisc":false, "timestamping":[]interface {}{"rx_software", "software"}, "macaddress":"d4:6d:6d:b6:cb:69", "device":"wlp58s0", "ipv6":[]interface {}{map[string]interface {}{"scope":"link", "prefix":"64", "address":"fe80::1090:23ec:9c5e:a5a7"}}, "active":true, "hw_timestamp_filters":[]interface {}{}}, "ansible_user_gecos":"Michael Hrivnak", "ansible_lo":map[string]interface {}{"hw_timestamp_filters":[]interface {}{}, "mtu":65536, "device":"lo", "timestamping":[]interface {}{"tx_software", "rx_software", "software"}, "active":true, "type":"loopback", "features":map[string]interface {}{"rx_checksumming":"on [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "tx_fcoe_segmentation":"off [fixed]", "tx_vlan_stag_hw_insert":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]", "rx_vlan_filter":"off [fixed]", "tx_gre_segmentation":"off [fixed]", "loopback":"on [fixed]", "tx_checksum_sctp":"on [fixed]", "tx_udp_tnl_segmentation":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_nocache_copy":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "tx_gre_csum_segmentation":"off [fixed]", "fcoe_mtu":"off [fixed]", "rx_all":"off [fixed]", "tx_lockless":"on [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "esp_hw_offload":"off [fixed]", "tx_tcp_mangleid_segmentation":"on", "tcp_segmentation_offload":"on", "generic_receive_offload":"on", "tx_checksum_ipv6":"off [fixed]", "tx_gso_robust":"off [fixed]", "tx_checksum_ip_generic":"on [fixed]", "tx_ipxip4_segmentation":"off [fixed]", "tx_checksumming":"on", "scatter_gather":"on", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_scatter_gather":"on [fixed]", "tx_gso_partial":"off [fixed]", "udp_fragmentation_offload":"off", "receive_hashing":"off [fixed]", "tx_scatter_gather_fraglist":"on [fixed]", "highdma":"on [fixed]", "rx_vlan_offload":"off [fixed]", "hw_tc_offload":"off [fixed]", "tx_tcp_ecn_segmentation":"on", "vlan_challenged":"on [fixed]", "rx_gro_hw":"off [fixed]", "tx_esp_segmentation":"off [fixed]", "tls_hw_record":"off [fixed]", "generic_segmentation_offload":"on", "tx_tcp_segmentation":"on", "large_receive_offload":"off [fixed]", "tx_ipxip6_segmentation":"off [fixed]", "tx_tcp6_segmentation":"on", "tx_sctp_segmentation":"on", "tx_checksum_fcoe_crc":"off [fixed]", "tx_vlan_offload":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "rx_fcs":"off [fixed]", "netns_local":"on [fixed]", "l2_fwd_offload":"off [fixed]"}, "promisc":false, "ipv4":map[string]interface {}{"address":"127.0.0.1", "broadcast":"host", "netmask":"255.0.0.0", "network":"127.0.0.0"}, "ipv6":[]interface {}{map[string]interface {}{"scope":"host", "prefix":"128", "address":"::1"}}}, "ansible_ssh_host_key_ed25519_public":"AAAAC3NzaC1lZDI1NTE5AAAAICtKfTlszEBZ7+CcxMjqacglawArIDyyjOOp+8nLZ5da", "ansible_distribution_release":"Twenty Eight", "ansible_effective_user_id":1000, "ansible_docker0":map[string]interface {}{"macaddress":"02:42:e9:bd:c9:1f", "active":false, "type":"bridge", "hw_timestamp_filters":[]interface {}{}, "id":"8000.0242e9bdc91f", "mtu":1500, "ipv4":map[string]interface {}{"broadcast":"global", "netmask":"255.255.0.0", "network":"172.17.0.0", "address":"172.17.0.1"}, "device":"docker0", "promisc":false, "ipv6":[]interface {}{map[string]interface {}{"scope":"link", "prefix":"64", "address":"fe80::42:e9ff:febd:c91f"}}, "timestamping":[]interface {}{"rx_software", "software"}, "features":map[string]interface {}{"rx_checksumming":"off [fixed]", "netns_local":"on [fixed]", "hw_tc_offload":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "tx_scatter_gather_fraglist":"on", "tx_tcp_ecn_segmentation":"on", "esp_hw_offload":"off [fixed]", "tx_gso_robust":"on", "tx_checksumming":"on", "vlan_challenged":"off [fixed]", "tx_scatter_gather":"on", "tx_gre_csum_segmentation":"on", "tx_checksum_fcoe_crc":"off [fixed]", "highdma":"on", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_ipxip6_segmentation":"on", "tx_nocache_copy":"off", "rx_all":"off [fixed]", "rx_fcs":"off [fixed]", "tx_gso_partial":"on", "tx_ipxip4_segmentation":"on", "scatter_gather":"on", "tx_vlan_stag_hw_insert":"on", "receive_hashing":"off [fixed]", "tx_lockless":"on [fixed]", "loopback":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "tx_udp_tnl_segmentation":"on", "tcp_segmentation_offload":"on", "l2_fwd_offload":"off [fixed]", "rx_vlan_stag_hw_parse":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "tx_fcoe_segmentation":"on", "esp_tx_csum_hw_offload":"off [fixed]", "tls_hw_record":"off [fixed]", "rx_vlan_filter":"off [fixed]", "tx_tcp_segmentation":"on", "fcoe_mtu":"off [fixed]", "tx_esp_segmentation":"on", "ntuple_filters":"off [fixed]", "tx_sctp_segmentation":"on", "generic_receive_offload":"on", "tx_tcp_mangleid_segmentation":"on", "large_receive_offload":"off [fixed]", "tx_gre_segmentation":"on", "tx_checksum_ipv6":"off [fixed]", "tx_vlan_offload":"on", "tx_udp_tnl_csum_segmentation":"on", "rx_gro_hw":"off [fixed]", "generic_segmentation_offload":"on", "udp_fragmentation_offload":"off", "rx_vlan_offload":"off [fixed]", "tx_tcp6_segmentation":"on", "tx_checksum_ip_generic":"on"}, "interfaces":[]interface {}{}, "stp":false}, "ansible_user_uid":1000, "ansible_distribution_version":"28", "ansible_system":"Linux", "ansible_bios_date":"01/24/2018", "ansible_selinux_python_present":false, "ansible_virbr1_nic":map[string]interface {}{"macaddress":"52:54:00:01:93:e9", "features":map[string]interface {}{"rx_all":"off [fixed]", "highdma":"off [fixed]", "tx_checksum_ipv6":"off [fixed]", "tx_scatter_gather_fraglist":"on", "tx_nocache_copy":"off", "tx_udp_tnl_segmentation":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]", "vlan_challenged":"off [fixed]", "tx_tcp_segmentation":"off [requested on]", "rx_vlan_filter":"off [fixed]", "generic_receive_offload":"on", "netns_local":"off [fixed]", "l2_fwd_offload":"off [fixed]", "rx_vlan_offload":"off [fixed]", "tx_vlan_stag_hw_insert":"on", "tx_scatter_gather":"on", "rx_gro_hw":"off [fixed]", "tx_gre_segmentation":"off [fixed]", "rx_fcs":"off [fixed]", "rx_vlan_stag_hw_parse":"off [fixed]", "hw_tc_offload":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "generic_segmentation_offload":"on", "udp_fragmentation_offload":"off", "tx_lockless":"on [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_ipxip4_segmentation":"off [fixed]", "tx_gre_csum_segmentation":"off [fixed]", "tx_checksum_fcoe_crc":"off [fixed]", "tx_tcp_ecn_segmentation":"off [requested on]", "esp_hw_offload":"off [fixed]", "tx_checksumming":"off", "tx_checksum_ipv4":"off [fixed]", "tx_vlan_offload":"on", "tx_gso_partial":"off [fixed]", "large_receive_offload":"off [fixed]", "tx_sctp_segmentation":"off [fixed]", "tx_fcoe_segmentation":"off [fixed]", "tx_gso_robust":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "tx_tcp6_segmentation":"off [requested on]", "tx_tcp_mangleid_segmentation":"off", "tx_ipxip6_segmentation":"off [fixed]", "tx_esp_segmentation":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "tcp_segmentation_offload":"off", "receive_hashing":"off [fixed]", "rx_checksumming":"off [fixed]", "tls_hw_record":"off [fixed]", "tx_checksum_ip_generic":"off [requested on]", "loopback":"off [fixed]", "fcoe_mtu":"off [fixed]", "scatter_gather":"on"}, "hw_timestamp_filters":[]interface {}{}, "device":"virbr1-nic", "timestamping":[]interface {}{"tx_software", "rx_software", "software"}, "mtu":1500, "promisc":true, "active":false, "type":"ether"}, "ansible_processor_count":1, "ansible_devices":map[string]interface {}{"dm-2":map[string]interface {}{"rotational":"0", "sas_address":interface {}(nil), "virtual":1, "host":"", "sectorsize":"512", "links":map[string]interface {}{"masters":[]interface {}{}, "labels":[]interface {}{}, "ids":[]interface {}{"dm-name-fedora-swap", "dm-uuid-LVM-ctIXuPquV3Kr2foFQ6XjPpTNIKGarF3a2w0SAyvVbI44bBZweGSa9aRC5n1hspz8"}, "uuids":[]interface {}{"1f44dc79-026e-446e-a532-05f693474dcc"}}, "removable":"0", "support_discard":"512", "partitions":map[string]interface {}{}, "holders":[]interface {}{}, "scheduler_mode":"", "vendor":interface {}(nil), "sectors":"4194304", "sas_device_handle":interface {}(nil), "model":interface {}(nil), "size":"2.00 GB"}, "dm-3":map[string]interface {}{"rotational":"0", "links":map[string]interface {}{"ids":[]interface {}{"dm-name-fedora-home", "dm-uuid-LVM-ctIXuPquV3Kr2foFQ6XjPpTNIKGarF3adt9E0zz3tozyfzIpdIbujjgFHHo86BLR"}, "uuids":[]interface {}{"c613d87a-8f23-4d1b-9402-0a33d3e16ba6"}, "masters":[]interface {}{}, "labels":[]interface {}{}}, "virtual":1, "host":"", "holders":[]interface {}{}, "sectorsize":"512", "scheduler_mode":"", "model":interface {}(nil), "partitions":map[string]interface {}{}, "vendor":interface {}(nil), "sectors":"104857600", "sas_device_handle":interface {}(nil), "sas_address":interface {}(nil), "removable":"0", "support_discard":"512", "size":"50.00 GB"}, "dm-0":map[string]interface {}{"model":interface {}(nil), "holders":[]interface {}{"fedora-root", "fedora-swap", "fedora-home"}, "rotational":"0", "virtual":1, "host":"", "partitions":map[string]interface {}{}, "sas_address":interface {}(nil), "sectorsize":"512", "removable":"0", "support_discard":"512", "vendor":interface {}(nil), "links":map[string]interface {}{"masters":[]interface {}{"dm-1", "dm-2", "dm-3"}, "labels":[]interface {}{}, "ids":[]interface {}{"dm-name-luks-859ee22d-0209-4fa7-b097-2af931856cde", "dm-uuid-CRYPT-LUKS1-859ee22d02094fa7b0972af931856cde-luks-859ee22d-0209-4fa7-b097-2af931856cde", "lvm-pv-uuid-Fu0LK2-ZadK-uH1m-HlEP-1bzw-sp8X-N1q5tQ"}, "uuids":[]interface {}{}}, "sas_device_handle":interface {}(nil), "scheduler_mode":"", "sectors":"318783488", "size":"152.01 GB"}, "dm-1":map[string]interface {}{"sas_address":interface {}(nil), "host":"", "sectorsize":"512", "removable":"0", "support_discard":"512", "model":interface {}(nil), "links":map[string]interface {}{"labels":[]interface {}{}, "ids":[]interface {}{"dm-name-fedora-root", "dm-uuid-LVM-ctIXuPquV3Kr2foFQ6XjPpTNIKGarF3axn1Q9q4ddinztuZM6zQ3b2Lb4D2RMoF3"}, "uuids":[]interface {}{"2ce59711-ff80-4fd9-9868-3ed436a5dd9f"}, "masters":[]interface {}{}}, "partitions":map[string]interface {}{}, "holders":[]interface {}{}, "rotational":"0", "sectors":"209715200", "sas_device_handle":interface {}(nil), "size":"100.00 GB", "scheduler_mode":"", "vendor":interface {}(nil), "virtual":1}, "sda":map[string]interface {}{"scheduler_mode":"cfq", "rotational":"1", "vendor":"Generic-", "sas_device_handle":interface {}(nil), "virtual":1, "removable":"1", "size":"0.00 Bytes", "sas_address":interface {}(nil), "model":"SD/MMC", "sectors":"0", "sectorsize":"512", "holders":[]interface {}{}, "links":map[string]interface {}{"uuids":[]interface {}{}, "masters":[]interface {}{}, "labels":[]interface {}{}, "ids":[]interface {}{"usb-Generic-_SD_MMC_20120501030900000-0:0"}}, "host":"USB controller: Intel Corporation Sunrise Point-LP USB 3.0 xHCI Controller (rev 21)", "support_discard":"0", "partitions":map[string]interface {}{}}, "nvme0n1":map[string]interface {}{"sas_device_handle":interface {}(nil), "sas_address":interface {}(nil), "size":"238.47 GB", "scheduler_mode":"none", "removable":"0", "vendor":interface {}(nil), "sectors":"500118192", "links":map[string]interface {}{"masters":[]interface {}{}, "labels":[]interface {}{}, "ids":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512", "nvme-eui.a0329948e408c100"}, "uuids":[]interface {}{}}, "virtual":1, "sectorsize":"512", "rotational":"0", "host":"Non-Volatile memory controller: Lenovo Device 0003", "support_discard":"512", "model":"LENSE20256GMSP34MEAT2TA", "partitions":map[string]interface {}{"nvme0n1p3":map[string]interface {}{"sectorsize":512, "uuid":"859ee22d-0209-4fa7-b097-2af931856cde", "links":map[string]interface {}{"masters":[]interface {}{"dm-0"}, "labels":[]interface {}{}, "ids":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512-part3", "nvme-eui.a0329948e408c100-part3"}, "uuids":[]interface {}{"859ee22d-0209-4fa7-b097-2af931856cde"}}, "sectors":"318787584", "start":"2508800", "holders":[]interface {}{"luks-859ee22d-0209-4fa7-b097-2af931856cde"}, "size":"152.01 GB"}, "nvme0n1p1":map[string]interface {}{"size":"200.00 MB", "sectorsize":512, "uuid":"4B09-5C93", "links":map[string]interface {}{"uuids":[]interface {}{"4B09-5C93"}, "masters":[]interface {}{}, "labels":[]interface {}{}, "ids":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512-part1", "nvme-eui.a0329948e408c100-part1"}}, "sectors":"409600", "start":"2048", "holders":[]interface {}{}}, "nvme0n1p2":map[string]interface {}{"holders":[]interface {}{}, "size":"1.00 GB", "sectorsize":512, "uuid":"072819ba-8d1e-4dfe-872d-96e302d53461", "links":map[string]interface {}{"uuids":[]interface {}{"072819ba-8d1e-4dfe-872d-96e302d53461"}, "masters":[]interface {}{}, "labels":[]interface {}{}, "ids":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512-part2", "nvme-eui.a0329948e408c100-part2"}}, "sectors":"2097152", "start":"411648"}}, "holders":[]interface {}{}}}, "ansible_distribution_file_parsed":true, "ansible_processor_vcpus":4, "ansible_lsb":map[string]interface {}{"codename":"TwentyEight", "id":"Fedora", "description":"Fedora release 28 (Twenty Eight)", "release":"28", "major_release":"28"}, "ansible_all_ipv4_addresses":[]interface {}{"192.168.39.1", "172.17.0.1", "192.168.122.1", "10.192.217.118", "192.168.42.1"}, "ansible_system_capabilities":[]interface {}{""}, "ansible_vnet1":map[string]interface {}{"mtu":1500, "promisc":true, "timestamping":[]interface {}{"tx_software", "rx_software", "software"}, "ipv6":[]interface {}{map[string]interface {}{"scope":"link", "prefix":"64", "address":"fe80::fcaa:a4ff:feda:245c"}}, "macaddress":"fe:aa:a4:da:24:5c", "features":map[string]interface {}{"generic_receive_offload":"on", "tx_gre_segmentation":"off [fixed]", "tx_tcp_ecn_segmentation":"on", "rx_vlan_stag_hw_parse":"off [fixed]", "rx_gro_hw":"off [fixed]", "ntuple_filters":"off [fixed]", "highdma":"off [fixed]", "loopback":"off [fixed]", "tx_gre_csum_segmentation":"off [fixed]", "tx_ipxip4_segmentation":"off [fixed]", "tx_checksum_ip_generic":"on", "tx_vlan_offload":"on", "tx_lockless":"on [fixed]", "tx_checksumming":"on", "vlan_challenged":"off [fixed]", "tx_esp_segmentation":"off [fixed]", "tx_checksum_ipv6":"off [fixed]", "large_receive_offload":"off [fixed]", "tx_udp_tnl_segmentation":"off [fixed]", "rx_all":"off [fixed]", "tx_gso_robust":"off [fixed]", "tx_sctp_segmentation":"off [fixed]", "rx_fcs":"off [fixed]", "rx_checksumming":"off [fixed]", "tx_checksum_fcoe_crc":"off [fixed]", "tx_scatter_gather":"on", "tx_fcoe_segmentation":"off [fixed]", "rx_vlan_filter":"off [fixed]", "tx_tcp_mangleid_segmentation":"off", "tx_vlan_stag_hw_insert":"on", "rx_vlan_stag_filter":"off [fixed]", "tx_tcp6_segmentation":"on", "esp_hw_offload":"off [fixed]", "tcp_segmentation_offload":"on", "l2_fwd_offload":"off [fixed]", "fcoe_mtu":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "hw_tc_offload":"off [fixed]", "receive_hashing":"off [fixed]", "tx_tcp_segmentation":"on", "tls_hw_record":"off [fixed]", "tx_nocache_copy":"off", "scatter_gather":"on", "tx_gso_partial":"off [fixed]", "tx_ipxip6_segmentation":"off [fixed]", "netns_local":"off [fixed]", "generic_segmentation_offload":"on", "tx_scatter_gather_fraglist":"on", "rx_vlan_offload":"off [fixed]", "udp_fragmentation_offload":"off"}, "hw_timestamp_filters":[]interface {}{}, "speed":10, "type":"ether", "device":"vnet1", "active":true}, "ansible_pkg_mgr":"dnf", "ansible_user_id":"mhrivnak", "ansible_real_user_id":1000, "ansible_virbr2_nic":map[string]interface {}{"macaddress":"52:54:00:a2:38:41", "features":map[string]interface {}{"hw_tc_offload":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "tx_scatter_gather_fraglist":"on", "tx_ipxip6_segmentation":"off [fixed]", "tx_checksum_sctp":"off [fixed]", "tx_tcp_segmentation":"off [requested on]", "tx_ipxip4_segmentation":"off [fixed]", "tcp_segmentation_offload":"off", "tx_checksum_fcoe_crc":"off [fixed]", "loopback":"off [fixed]", "rx_gro_hw":"off [fixed]", "ntuple_filters":"off [fixed]", "tx_sctp_segmentation":"off [fixed]", "tx_lockless":"on [fixed]", "l2_fwd_offload":"off [fixed]", "rx_fcs":"off [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "tx_fcoe_segmentation":"off [fixed]", "esp_hw_offload":"off [fixed]", "tx_vlan_stag_hw_insert":"on", "udp_fragmentation_offload":"off", "rx_all":"off [fixed]", "scatter_gather":"on", "rx_vlan_stag_hw_parse":"off [fixed]", "tx_nocache_copy":"off", "receive_hashing":"off [fixed]", "tls_hw_record":"off [fixed]", "rx_vlan_stag_filter":"off [fixed]", "rx_checksumming":"off [fixed]", "netns_local":"off [fixed]", "rx_vlan_offload":"off [fixed]", "tx_checksum_ip_generic":"off [requested on]", "tx_checksum_ipv6":"off [fixed]", "highdma":"off [fixed]", "generic_segmentation_offload":"on", "generic_receive_offload":"on", "tx_gso_robust":"off [fixed]", "tx_checksumming":"off", "fcoe_mtu":"off [fixed]", "large_receive_offload":"off [fixed]", "tx_esp_segmentation":"off [fixed]", "tx_gre_segmentation":"off [fixed]", "rx_vlan_filter":"off [fixed]", "tx_tcp_ecn_segmentation":"off [requested on]", "vlan_challenged":"off [fixed]", "tx_gso_partial":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "tx_scatter_gather":"on", "tx_udp_tnl_segmentation":"off [fixed]", "tx_tcp6_segmentation":"off [requested on]", "tx_tcp_mangleid_segmentation":"off", "tx_gre_csum_segmentation":"off [fixed]", "tx_udp_tnl_csum_segmentation":"off [fixed]", "tx_vlan_offload":"on"}, "hw_timestamp_filters":[]interface {}{}, "device":"virbr2-nic", "promisc":true, "active":false, "type":"ether", "mtu":1500, "timestamping":[]interface {}{"tx_software", "rx_software", "software"}}, "ansible_processor_cores":2, "ansible_ssh_host_key_ecdsa_public":"AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNshzKu3Ht3hQ7zzm/93GdUZ7i3A6YkMGqfFSqh1cR+uRcJN5yO1mpX85d/hQamGiOmFHyFz7v/MBEikDMCGIjc=", "ansible_system_vendor":"LENOVO", "gather_subset":[]interface {}{"all"}, "ansible_device_links":map[string]interface {}{"masters":map[string]interface {}{"nvme0n1p3":[]interface {}{"dm-0"}, "dm-0":[]interface {}{"dm-1", "dm-2", "dm-3"}}, "labels":map[string]interface {}{}, "ids":map[string]interface {}{"dm-0":[]interface {}{"dm-name-luks-859ee22d-0209-4fa7-b097-2af931856cde", "dm-uuid-CRYPT-LUKS1-859ee22d02094fa7b0972af931856cde-luks-859ee22d-0209-4fa7-b097-2af931856cde", "lvm-pv-uuid-Fu0LK2-ZadK-uH1m-HlEP-1bzw-sp8X-N1q5tQ"}, "nvme0n1p1":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512-part1", "nvme-eui.a0329948e408c100-part1"}, "nvme0n1p2":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512-part2", "nvme-eui.a0329948e408c100-part2"}, "sda":[]interface {}{"usb-Generic-_SD_MMC_20120501030900000-0:0"}, "nvme0n1":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512", "nvme-eui.a0329948e408c100"}, "nvme0n1p3":[]interface {}{"nvme-LENSE20256GMSP34MEAT2TA_FBFB18030C10000512-part3", "nvme-eui.a0329948e408c100-part3"}, "dm-2":[]interface {}{"dm-name-fedora-swap", "dm-uuid-LVM-ctIXuPquV3Kr2foFQ6XjPpTNIKGarF3a2w0SAyvVbI44bBZweGSa9aRC5n1hspz8"}, "dm-3":[]interface {}{"dm-name-fedora-home", "dm-uuid-LVM-ctIXuPquV3Kr2foFQ6XjPpTNIKGarF3adt9E0zz3tozyfzIpdIbujjgFHHo86BLR"}, "dm-1":[]interface {}{"dm-name-fedora-root", "dm-uuid-LVM-ctIXuPquV3Kr2foFQ6XjPpTNIKGarF3axn1Q9q4ddinztuZM6zQ3b2Lb4D2RMoF3"}}, "uuids":map[string]interface {}{"nvme0n1p1":[]interface {}{"4B09-5C93"}, "nvme0n1p2":[]interface {}{"072819ba-8d1e-4dfe-872d-96e302d53461"}, "nvme0n1p3":[]interface {}{"859ee22d-0209-4fa7-b097-2af931856cde"}, "dm-2":[]interface {}{"1f44dc79-026e-446e-a532-05f693474dcc"}, "dm-3":[]interface {}{"c613d87a-8f23-4d1b-9402-0a33d3e16ba6"}, "dm-1":[]interface {}{"2ce59711-ff80-4fd9-9868-3ed436a5dd9f"}}}, "module_setup":true, "ansible_swapfree_mb":1463, "ansible_distribution_major_version":"28", "ansible_machine":"x86_64", "ansible_fqdn":"localhost.localdomain", "ansible_virtualization_type":"kvm", "ansible_python":map[string]interface {}{"version_info":[]interface {}{2, 7, 15, "final", 0}, "executable":"/home/mhrivnak/pythons/ansible-events/bin/python", "version":map[string]interface {}{"micro":15, "major":2, "releaselevel":"final", "serial":0, "minor":7}, "type":"CPython", "has_sslcontext":true}, "ansible_enp0s31f6":map[string]interface {}{"active":false, "speed":-1, "macaddress":"8c:16:45:54:80:d5", "type":"ether", "module":"e1000e", "mtu":1500, "device":"enp0s31f6", "promisc":false, "hw_timestamp_filters":[]interface {}{"none", "all", "ptp_v1_l4_sync", "ptp_v1_l4_delay_req", "ptp_v2_l4_sync", "ptp_v2_l4_delay_req", "ptp_v2_l2_sync", "ptp_v2_l2_delay_req", "ptp_v2_event", "ptp_v2_sync", "ptp_v2_delay_req"}, "phc_index":0, "features":map[string]interface {}{"tx_gso_robust":"off [fixed]", "tx_tcp_mangleid_segmentation":"off", "vlan_challenged":"off [fixed]", "udp_fragmentation_offload":"off", "tx_checksum_fcoe_crc":"off [fixed]", "generic_receive_offload":"on", "tx_scatter_gather_fraglist":"off [fixed]", "highdma":"on [fixed]", "tx_ipxip6_segmentation":"off [fixed]", "tx_gre_csum_segmentation":"off [fixed]", "l2_fwd_offload":"off [fixed]", "tx_checksum_ipv4":"off [fixed]", "loopback":"off [fixed]", "tx_vlan_stag_hw_insert":"off [fixed]", "tx_udp_tnl_segmentation":"off [fixed]", "tx_nocache_copy":"off", "esp_hw_offload":"off [fixed]", "tx_gso_partial":"off [fixed]", "rx_vlan_offload":"on", "ntuple_filters":"off [fixed]", "tx_fcoe_segmentation":"off [fixed]", "tx_vlan_offload":"on", "tx_lockless":"off [fixed]", "tx_scatter_gather":"on", "rx_gro_hw":"off [fixed]", "tcp_segmentation_offload":"on", "tls_hw_record":"off [fixed]", "hw_tc_offload":"off [fixed]", "rx_vlan_filter":"off [fixed]", "scatter_gather":"on", "rx_vlan_stag_filter":"off [fixed]", "large_receive_offload":"off [fixed]", "rx_udp_tunnel_port_offload":"off [fixed]", "rx_vlan_stag_hw_parse":"off [fixed]", "esp_tx_csum_hw_offload":"off [fixed]", "tx_checksum_ip_generic":"on", "tx_tcp_ecn_segmentation":"off [fixed]", "tx_ipxip4_segmentation":"off [fixed]", "tx_checksumming":"on", "netns_local":"off [fixed]", "generic_segmentation_offload":"on", "tx_esp_segmentation":"off [fixed]", "tx_gre_segmentation":"off [fixed]", "tx_tcp6_segmentation":"on", "fcoe_mtu":"off [fixed]", "tx_tcp_segmentation":"on", "tx_checksum_ipv6":"off [fixed]", "rx_fcs":"off", "tx_checksum_sctp":"off [fixed]", "receive_hashing":"on", "rx_checksumming":"on", "tx_udp_tnl_csum_segmentation":"off [fixed]", "tx_sctp_segmentation":"off [fixed]", "rx_all":"off"}, "pciid":"0000:00:1f.6", "timestamping":[]interface {}{"tx_hardware", "tx_software", "rx_hardware", "rx_software", "software", "raw_hardware"}}, "ansible_machine_id":"c6ec528833bc4b51803cc178a2f2463e", "ansible_user_gid":1000, "ansible_os_family":"RedHat"}, "_ansible_parsed":true, "_ansible_no_log":false, "changed":false, "_ansible_verbose_override":true}, "task_action":"setup", "host":"localhost", "task_path":""}  component=logging_event_handler event_type=runner_on_ok gvk="app.example.com/v1alpha1, Kind=Database" name=example namespace=default task="Gathering Facts"

duplicate GVK in config file should fail startup

In the config file at /opt/ansible/config.yaml, users create a mapping of GVK to an ansible role or playbook. It is not valid for a GVK to appear twice in the file. In that case, the operator should notice during startup and exit with an error code and log message.

As a human, I find the output of the ansible-operator difficult to read

Summary

I think we can trim down and enhance the output from the ansible-operator such that users will have an easier time using and debugging ansible-operator. After gathering feedback here, I plan to submit a PR to operator-sdk.

Current and proposed log output

Here's what the current log output looks like running my sample operator user operator-sdk up local.

This is a draft of the proposed log output for the same events.

Goals in formatting the logs

  • Add more visual separation between log messages
  • Strip log messages down to minimize visual overload
  • Give the user an easy way to access the full Ansible logs for a particular job (suggested by @alaypatel07 and @djzager)
  • Balance human readability with machine readability by keeping log message content free of newline \n chars in the case that we ever want logs to be interpreted by another system (suggested by @fabianvf )

Changes suggested, as shown in the proposed log output:

  • Add visual separation between log events by printing a line of ***** chars before each log, and a newline after each log

  • Shorten the job identifier (at least in the logs) so that it takes up less space on-screen, and fits into short-term memory better when visually scanning across logs. We could consider switching to alphanumeric to compact while keeping large pool of IDs.

  • Remove the component, and gvk fields from each log message, and combine Name and Kind to become Resource=<Kind>/<Name>. From my (limited) perspective, component and gvk are adequately represented by the Kind field. Please correct me if there is a good reason to have these in. If these are needed in special cases I'd like to suggest we have a DEBUG mode with additional logs.

  • Add visual emphasis around the "log metadata" fields (job, resource, namespace) so that they can easily be picked out at the end of long log message lines. Also re-arrange meta fields in output so that job is first.

  • Print a new log message when an ansible-runner job is started, as a matching pair to the exited successfully message. In this message, dynamically generate the kubectl/oc command that can be used to view the full logs for a particular ansible-runner job

Eager to hear thoughts on these changes.

resourceVersion for the provided watch is too old

Unclear to me if this is a standard error or specific to something the ansible-operator is doing so figured I'd report it:

ERROR: logging before flag.Parse: W0718 18:45:08.827252       1 reflector.go:341] github.com/automationbroker/ansible-operator/vendor/github.com/operator-framework/operator-sdk/pkg/sdk/informer.go:80: watch of *unstructured.Unstructured ended with: The resourceVersion for the provided watch is too old.

Proxy code leads to resources being created by `system:anonymous` leads to 403

I mentioned this to @fabianvf but figure its always good to track issues. New proxy code leads to resources being created by system:anonymous instead of the service account associated with the deployment:

TASK [service-accounts : foreman-anyuid service account] ***********************
task path: /opt/ansible/roles/service-accounts/tasks/main.yml:2
fatal: [localhost]: FAILED! => {"changed": false, "error": 403, "msg": "Failed to retrieve requested object: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"serviceaccounts \\\"foreman-anyuid\\\" is forbidden: User \\\"system:anonymous\\\" cannot get serviceaccounts in the namespace \\\"foreman\\\": User \\\"system:anonymous\\\" cannot get serviceaccounts in project \\\"foreman\\\"\",\"reason\":\"Forbidden\",\"details\":{\"name\":\"foreman-anyuid\",\"kind\":\"serviceaccounts\"},\"code\":403}\n", "reason": "Forbidden", "status": 403}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.