mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-03-27 05:43:02 +00:00
k8s_log - fix issue when required name is not provided, add all_containers support (#528)
k8s_log - fix issue when required name is not provided, add all_containers support SUMMARY Fixes issue when the required name is not provided, closes #514 all support for all_containers option ISSUE TYPE Bugfix Pull Request Feature Pull Request COMPONENT NAME k8s_log ADDITIONAL INFORMATION Reviewed-by: Mike Graves <mgraves@redhat.com> Reviewed-by: Jill R <None>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
bugfixes:
|
||||
- k8s_log - fix exception raised when the name is not provided for resources requiring. (https://github.com/ansible-collections/kubernetes.core/issues/514)
|
||||
minor_changes:
|
||||
- k8s_log - add the ``all_containers`` for retrieving all containers' logs in the pod(s).
|
||||
@@ -51,7 +51,8 @@ options:
|
||||
description:
|
||||
- Use to specify the container within a pod to grab the log from.
|
||||
- If there is only one container, this will default to that container.
|
||||
- If there is more than one container, this option is required.
|
||||
- If there is more than one container, this option is required or set I(all_containers) to C(true).
|
||||
- mutually exclusive with C(all_containers).
|
||||
required: no
|
||||
type: str
|
||||
since_seconds:
|
||||
@@ -73,6 +74,12 @@ options:
|
||||
required: no
|
||||
type: int
|
||||
version_added: '2.4.0'
|
||||
all_containers:
|
||||
description:
|
||||
- If set to C(true), retrieve all containers' logs in the pod(s).
|
||||
- mutually exclusive with C(container).
|
||||
type: bool
|
||||
version_added: '2.4.0'
|
||||
|
||||
requirements:
|
||||
- "python >= 3.6"
|
||||
@@ -114,6 +121,13 @@ EXAMPLES = r"""
|
||||
name: example
|
||||
tail_lines: 100
|
||||
register: log
|
||||
|
||||
# This will get the logs from all containers in Pod
|
||||
- name: Get the logs from all containers in pod
|
||||
kubernetes.core.k8s_log:
|
||||
namespace: testing
|
||||
name: some-pod
|
||||
all_containers: true
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
@@ -131,6 +145,7 @@ log_lines:
|
||||
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import (
|
||||
AnsibleModule,
|
||||
@@ -170,11 +185,35 @@ def argspec():
|
||||
label_selectors=dict(type="list", elements="str", default=[]),
|
||||
previous=dict(type="bool", default=False),
|
||||
tail_lines=dict(type="int"),
|
||||
all_containers=dict(type="bool"),
|
||||
)
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def get_exception_message(exc):
|
||||
try:
|
||||
d = json.loads(exc.body.decode("utf8"))
|
||||
return d["message"]
|
||||
except Exception:
|
||||
return exc
|
||||
|
||||
|
||||
def list_containers_in_pod(svc, resource, namespace, name):
|
||||
try:
|
||||
result = svc.client.get(resource, name=name, namespace=namespace)
|
||||
containers = [
|
||||
c["name"] for c in result.to_dict()["status"]["containerStatuses"]
|
||||
]
|
||||
return containers
|
||||
except Exception as exc:
|
||||
raise CoreException(
|
||||
"Unable to retrieve log from Pod due to: {0}".format(
|
||||
get_exception_message(exc)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def execute_module(svc, params):
|
||||
name = params.get("name")
|
||||
namespace = params.get("namespace")
|
||||
@@ -206,6 +245,11 @@ def execute_module(svc, params):
|
||||
name = instances.items[0].metadata.name
|
||||
resource = v1_pods
|
||||
|
||||
if "base" not in resource.log.urls and not name:
|
||||
raise CoreException(
|
||||
"name must be provided for resources that do not support namespaced base url"
|
||||
)
|
||||
|
||||
kwargs = {}
|
||||
if params.get("container"):
|
||||
kwargs["query_params"] = {"container": params["container"]}
|
||||
@@ -223,19 +267,28 @@ def execute_module(svc, params):
|
||||
{"tailLines": params["tail_lines"]}
|
||||
)
|
||||
|
||||
pod_containers = [None]
|
||||
if params.get("all_containers"):
|
||||
pod_containers = list_containers_in_pod(svc, resource, namespace, name)
|
||||
|
||||
log = ""
|
||||
try:
|
||||
response = resource.log.get(
|
||||
name=name, namespace=namespace, serialize=False, **kwargs
|
||||
)
|
||||
for container in pod_containers:
|
||||
if container is not None:
|
||||
kwargs.setdefault("query_params", {}).update({"container": container})
|
||||
response = resource.log.get(
|
||||
name=name, namespace=namespace, serialize=False, **kwargs
|
||||
)
|
||||
log += response.data.decode("utf8")
|
||||
except ApiException as exc:
|
||||
if exc.reason == "Not Found":
|
||||
raise CoreException("Pod {0}/{1} not found.".format(namespace, name))
|
||||
raise CoreException(
|
||||
"Unable to retrieve log from Pod due to: {0}".format(exc.reason)
|
||||
"Unable to retrieve log from Pod due to: {0}".format(
|
||||
get_exception_message(exc)
|
||||
)
|
||||
)
|
||||
|
||||
log = response.data.decode("utf8")
|
||||
|
||||
return {"changed": False, "log": log, "log_lines": log.split("\n")}
|
||||
|
||||
|
||||
@@ -290,7 +343,10 @@ def extract_selectors(instance):
|
||||
|
||||
def main():
|
||||
module = AnsibleK8SModule(
|
||||
module_class=AnsibleModule, argument_spec=argspec(), supports_check_mode=True
|
||||
module_class=AnsibleModule,
|
||||
argument_spec=argspec(),
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=[("container", "all_containers")],
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -165,6 +165,79 @@
|
||||
assert:
|
||||
that: tailed_log.log_lines | length == 5 + 1
|
||||
|
||||
# Trying to call module without name and label_selectors
|
||||
- name: Retrieve without neither name nor label_selectors provided
|
||||
k8s_log:
|
||||
namespace: "{{ test_namespace }}"
|
||||
register: noname_log
|
||||
ignore_errors: true
|
||||
|
||||
- name: Ensure task failed
|
||||
assert:
|
||||
that:
|
||||
- noname_log is failed
|
||||
- 'noname_log.msg == "name must be provided for resources that do not support namespaced base url"'
|
||||
|
||||
# Test retrieve all containers logs
|
||||
- name: Create deployments
|
||||
k8s:
|
||||
namespace: "{{ test_namespace }}"
|
||||
wait: yes
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
wait_condition:
|
||||
type: Complete
|
||||
status: 'True'
|
||||
definition:
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: multicontainer-log
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: p01
|
||||
image: busybox
|
||||
command: ['sh']
|
||||
args: ['-c', 'for i in $(seq 0 9); do echo $i; done']
|
||||
- name: p02
|
||||
image: busybox
|
||||
command: ['sh']
|
||||
args: ['-c', 'for i in $(seq 10 19); do echo $i; done']
|
||||
restartPolicy: Never
|
||||
|
||||
- name: Retrieve logs from all containers
|
||||
k8s_log:
|
||||
api_version: batch/v1
|
||||
kind: Job
|
||||
namespace: "{{ test_namespace }}"
|
||||
name: multicontainer-log
|
||||
all_containers: true
|
||||
register: all_logs
|
||||
|
||||
- name: Retrieve logs from first job
|
||||
k8s_log:
|
||||
api_version: batch/v1
|
||||
kind: Job
|
||||
namespace: "{{ test_namespace }}"
|
||||
name: multicontainer-log
|
||||
container: p01
|
||||
register: log_1
|
||||
|
||||
- name: Retrieve logs from second job
|
||||
k8s_log:
|
||||
api_version: batch/v1
|
||||
kind: Job
|
||||
namespace: "{{ test_namespace }}"
|
||||
name: multicontainer-log
|
||||
container: p02
|
||||
register: log_2
|
||||
|
||||
- name: Validate that log using all_containers=true is the sum of all logs
|
||||
assert:
|
||||
that:
|
||||
- all_logs.log == (log_1.log + log_2.log)
|
||||
|
||||
always:
|
||||
- name: ensure that namespace is removed
|
||||
k8s:
|
||||
|
||||
Reference in New Issue
Block a user