diff --git a/README.md b/README.md index d12056a..5f7f899 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ * [IPV4 enforcement](#ipv4-enforcement) * [Upgrade](#upgrade) - >Note: Please see the release notes for what's new in the latest release. ## Additional Documentation @@ -30,15 +29,15 @@ - For service broker - a k8s distribution that supports service catalog (see also: service-catalog) - Access to DockerHub, RedHat Container Catalog or a private repository that can serve the required images -For Service Broker, please see examples/with_service_broker_rhel.yaml. RedHat certified images are available on: https://access.redhat.com/containers/#/product/71f6d1bb3408bd0d +For Service Broker, please see openshift/with_service_broker_rhel.yaml. RedHat certified images are available on: https://access.redhat.com/containers/#/product/71f6d1bb3408bd0d The following are the images and tags for this release: -Redis Enterprise - `redislabs/redis:5.4.10-22` or `redislabs/redis:5.4.10-22b.rhel7-openshift` (for DockerHub pulls, ommit the 'b' notation) +Redis Enterprise - `redislabs/redis:5.4.14-19` or `redislabs/redis:5.4.14-19.rhel7-openshift` (for DockerHub pulls, ommit the 'b' notation) -Operator - `redislabs/operator:5.4.10-8` or `redislabs/operator:5.4.10-8.rhel7` +Operator - `redislabs/operator:5.4.14-2` or `redislabs/operator:5.4.14-2.rhel7` -Services Rigger - `redislabs/k8s-controller:5.4.10-8` or `redislabs/k8s-controller:5.4.10-8b.rhel7` (for DockerHub pulls, ommit the 'b' notation) +Services Rigger - `redislabs/k8s-controller:5.4.14-2` or `redislabs/k8s-controller:5.4.14-2.rhel7` Service Broker - `redislabs/service-broker:78_4b9b17f` or `redislabs/service-broker:78_4b9b17f.rhel7` @@ -47,6 +46,7 @@ The "Basic" installations deploys the operator from the current release with the This is the fastest way to get up and running with a new cluster in most environments. Other Kubernetes distributions setup process as well as other custom configurations are referenced in this repository. +Note: The v1 version of the operator is recommended to use and referenced in yaml file names below. However, the v1alpha1 version is the only supported version to run on K8s 1.9 and 1.10. For those versions, use the relevant yamls for v1alpha1. 1. Create a new namespace: ```bash @@ -88,7 +88,7 @@ A typical response may look like this: |redis-enterprise-operator|1 | 1 | 1 | 1 | 2m | ``` -4. Create A Redis Enterprise Cluster using the default configuration, which is suitable for development type deployments and works in typical scenarios. For more advanced deployment options you may choose the configuration relevant for you - see the index at the top for documentation references that cover many scenarios and the examples in the example folder. +4. Create A Redis Enterprise Cluster using the default configuration, which is suitable for development type deployments and works in typical scenarios. For more advanced deployment options you may choose the configuration relevant for you - see the index at the top for documentation references that cover many scenarios. ```bash kubectl apply -f crds/app_v1_redisenterprisecluster_cr.yaml @@ -135,7 +135,7 @@ oc adm policy add-scc-to-group redis-enterprise-scc system:serviceaccounts:my-pr 4. Deploy the OpenShift operator bundle: ```bash -kubectl apply -f openshift.bundle.yaml +oc apply -f openshift.bundle.yaml ``` Apply the `RedisEnterpriseCluster` resource with RHEL7 based images @@ -152,7 +152,7 @@ Redis Image redisEnterpriseImageSpec: imagePullPolicy: IfNotPresent repository: redislabs/redis - versionTag: 5.4.10-22 + versionTag: 5.4.14-19 ``` Persistence @@ -265,21 +265,21 @@ For example: redisEnterpriseImageSpec: imagePullPolicy: IfNotPresent repository: harbor.corp.local/redisenterprise/redis - versionTag: 5.4.10-22 + versionTag: 5.4.14-19 ``` ```yaml redisEnterpriseServicesRiggerImageSpec: imagePullPolicy: IfNotPresent repository: harbor.corp.local/redisenterprise/k8s-controller - versionTag: 5.4.10-8 + versionTag: 5.4.14-2 ``` ```yaml bootstrapperImageSpec: imagePullPolicy: IfNotPresent repository: harbor.corp.local/redisenterprise/operator - versionTag: 5.4.10-8 + versionTag: 5.4.14-2 ``` In Operator Deployment spec (operator.yaml): @@ -292,7 +292,7 @@ spec: spec: containers: - name: redis-enterprise-operator - image: harbor.corp.local/redisenterprise/operator:5.4.10-8 + image: harbor.corp.local/redisenterprise/operator:5.4.14-2 ``` Image specification follow the [K8s Container schema](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#container-v1-core). diff --git a/bundle.yaml b/bundle.yaml index 2b3956d..695b38d 100644 --- a/bundle.yaml +++ b/bundle.yaml @@ -98,7 +98,7 @@ spec: served: true storage: true --- -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: redis-enterprise-operator @@ -116,7 +116,7 @@ spec: containers: - name: redis-enterprise-operator # Replace this with the built image name - image: redislabs/operator:5.4.10-8 + image: redislabs/operator:5.4.14-2 command: - redis-enterprise-operator imagePullPolicy: Always diff --git a/crds/app_v1alpha1_redisenterprisedatabase_cr.yaml b/crds/app_v1alpha1_redisenterprisedatabase_cr.yaml new file mode 100644 index 0000000..7b59925 --- /dev/null +++ b/crds/app_v1alpha1_redisenterprisedatabase_cr.yaml @@ -0,0 +1,7 @@ +apiVersion: app.redislabs.com/v1alpha1 +kind: RedisEnterpriseDatabase +metadata: + name: example-redisenterprisedatabase +spec: + redisEnterpriseCluster: + name: example-redisenterprisecluster diff --git a/crds/app_v1alpha1_redisenterprisedatabase_crd.yaml b/crds/app_v1alpha1_redisenterprisedatabase_crd.yaml new file mode 100644 index 0000000..e0677e0 --- /dev/null +++ b/crds/app_v1alpha1_redisenterprisedatabase_crd.yaml @@ -0,0 +1,21 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: redisenterprisedatabases.app.redislabs.com +spec: + group: app.redislabs.com + names: + kind: RedisEnterpriseDatabase + listKind: RedisEnterpriseDatabaseList + plural: redisenterprisedatabases + singular: redisenterprisedatabase + shortNames: + - redb + scope: Namespaced + subresources: + status: {} + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/docs/operator.md b/docs/operator.md index 586191c..2bc3ab8 100644 --- a/docs/operator.md +++ b/docs/operator.md @@ -156,6 +156,7 @@ RedisEnterpriseClusterSpec defines the desired state of RedisEnterpriseCluster | priorityClassName | Adds the priority class to pods managed by the operator | string | | false | | volumes | additional volumes | []v1.Volume | | false | | redisEnterpriseVolumeMounts | additional volume mounts within the redis enterprise containers | []v1.VolumeMount | | false | +| podAnnotations | pod annotations | map[string]string | | false | [Back to Table of Contents](#table-of-contents) ### RedisEnterpriseClusterStatus diff --git a/docs/topics.md b/docs/topics.md index 08ea527..93ddc9e 100644 --- a/docs/topics.md +++ b/docs/topics.md @@ -171,21 +171,21 @@ For example: redisEnterpriseImageSpec: imagePullPolicy: IfNotPresent repository: harbor.corp.local/redisenterprise/redis - versionTag: 5.4.6-18 + versionTag: 5.4.14-19 ``` ```yaml redisEnterpriseServicesRiggerImageSpec: imagePullPolicy: IfNotPresent repository: harbor.corp.local/redisenterprise/k8s-controller - versionTag: 5.4.6-1186 + versionTag: 5.4.14-2 ``` ```yaml bootstrapperImageSpec: imagePullPolicy: IfNotPresent repository: harbor.corp.local/redisenterprise/operator - versionTag: 5.4.6-1186 + versionTag: 5.4.14-2 ``` In Operator Deployment spec (operator.yaml): @@ -198,7 +198,7 @@ spec: spec: containers: - name: redis-enterprise-operator - image: harbor.corp.local/redisenterprise/operator:5.4.6-1186 + image: harbor.corp.local/redisenterprise/operator:5.4.14-2 ``` Image specification follow the [K8s Container schema](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#container-v1-core). diff --git a/examples/legacy.yaml b/examples/legacy.yaml deleted file mode 100644 index 2cdd753..0000000 --- a/examples/legacy.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: "app.redislabs.com/v1" -kind: "RedisEnterpriseCluster" -metadata: - name: "redis-enterprise" -spec: - nodes: 3 - persistentSpec: - enabled: true - storageClassName: "gp2" # ! edit according to infrastructure - uiServiceType: LoadBalancer - username: "admin@redislabs.com" - redisEnterpriseNodeResources: - limits: - cpu: "4000m" - memory: 4Gi - requests: - cpu: "4000m" - memory: 4Gi diff --git a/examples/persistent.yaml b/examples/persistent.yaml deleted file mode 100644 index 98cd2ac..0000000 --- a/examples/persistent.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: "app.redislabs.com/v1" -kind: "RedisEnterpriseCluster" -metadata: - name: "redis-enterprise" -spec: - nodes: 3 - persistentSpec: - enabled: true - storageClassName: "gp2" # edit according to infrastructure diff --git a/examples/simple.yaml b/examples/simple.yaml deleted file mode 100644 index 8010eee..0000000 --- a/examples/simple.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: "app.redislabs.com/v1" -kind: "RedisEnterpriseCluster" -metadata: - name: "redis-enterprise" -spec: - nodes: 3 diff --git a/examples/with_service_broker.yaml b/examples/with_service_broker.yaml deleted file mode 100644 index 8c7cb6c..0000000 --- a/examples/with_service_broker.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: "app.redislabs.com/v1" -kind: "RedisEnterpriseCluster" -metadata: - name: "redis-enterprise" -spec: - nodes: 3 - serviceBrokerSpec: - enabled: true - persistentSpec: - storageClassName: "gp2" diff --git a/examples/with_service_broker_rhel.yaml b/examples/with_service_broker_rhel.yaml deleted file mode 100644 index 4e04447..0000000 --- a/examples/with_service_broker_rhel.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: "app.redislabs.com/v1" -kind: "RedisEnterpriseCluster" -metadata: - name: "redis-enterprise" -spec: - nodes: 3 - serviceBrokerSpec: - enabled: true - persistentSpec: - storageClassName: "gp2" - redisEnterpriseImageSpec: - imagePullPolicy: IfNotPresent - repository: redislabs/redis - versionTag: 5.4.6-18.rhel7-openshift diff --git a/log_collector/log_collector.py b/log_collector/log_collector.py index 4ad7ba1..efbef57 100755 --- a/log_collector/log_collector.py +++ b/log_collector/log_collector.py @@ -1,8 +1,10 @@ #!/usr/bin/env python -# Redis Enterprise Cluster log collector script. -# Creates a directory with output of kubectl for several API objects and for pods logs -# unless pass a -n parameter will run on current namespace. Run with -h to see options +""" Redis Enterprise Cluster log collector script. +Creates a directory with output of kubectl for +several API objects and for pods logs unless pass a -n +parameter will run on current namespace. Run with -h to see options +""" import argparse import logging @@ -17,42 +19,51 @@ import json import signal +# pylint: disable=locally-disabled, invalid-name logger = logging.getLogger("log collector") TIME_FORMAT = time.strftime("%Y%m%d-%H%M%S") -api_resources = [ +API_RESOURCES = [ "RedisEnterpriseCluster", + "RedisEnterpriseDatabase", "StatefulSet", "Deployment", - "Services", + "Service", "ConfigMap", "Routes", "Ingress", - "Roles", - "Rolebindings", - "pv", - "pvc", - "Nodes", - "pdb", - "quota", + "Role", + "RoleBinding", + "PersistentVolume", + "PersistentVolumeClaim", + "Node", + "PodDisruptionBudget", + "ResourceQuota", "Endpoints", - "Pods", - "NetworkPolicies" + "Pod", + "NetworkPolicy", + "CustomResourceDefinition" ] def make_dir(directory): + """ + Create an directory if not exists + """ if not os.path.exists(directory): # noinspection PyBroadException try: os.mkdir(directory) - except Exception: - logger.exception("Could not create directory %s - exiting", directory) + except OSError as ex: + logger.warning("Failed to create directory %s: %s", directory, ex) sys.exit() def run(namespace, output_dir): + """ + Collect logs + """ if not namespace: namespace = get_namespace_from_config() @@ -80,20 +91,31 @@ def run(namespace, output_dir): def get_redis_enterprise_debug_info(namespace, output_dir): """ - Connects to an RS cluster node, creates and copies debug info package from the pod + Connects to an RS cluster node, + creates and copies debug info package from a pod, preferably one that passes readiness probe """ - pod_names = get_pod_names(namespace, selector='redis.io/role=node') - if not pod_names: + rs_pods = get_pods(namespace, selector='redis.io/role=node') + if not rs_pods: logger.warning("Cannot find redis enterprise pod") return + pod_names = [] + for pod in rs_pods: + if all(container_status['ready'] for container_status in pod['status']['containerStatuses']): + pod_names.append(pod['metadata']['name']) + if not pod_names: + logger.warning("Cannot find a ready redis enterprise pod, will use a non-ready pod") + pod_names = [pod['metadata']['name'] for pod in rs_pods] + pod_name = pod_names[0] cont = "redis-enterprise-node" prog = "/opt/redislabs/bin/rladmin" - cmd = "kubectl -n {} exec {} -c {} {} cluster debug_info path /tmp".format(namespace, pod_name, cont, prog) - rc, out = run_shell_command(cmd) + cmd = "kubectl -n {} exec {} -c {} {} cluster debug_info path /tmp"\ + .format(namespace, pod_name, cont, prog) + return_code, out = run_shell_command(cmd) if "Downloading complete" not in out: - logger.warning("Failed running rladmin command in pod: {}".format(out.rstrip())) + logger.warning("Failed running rladmin command in pod: %s", + out.rstrip()) return # get the debug file name @@ -101,19 +123,24 @@ def get_redis_enterprise_debug_info(namespace, output_dir): if match: debug_file_path = match.group(1) debug_file_name = match.group(2) - logger.info("debug info created on pod {} in path {}".format(pod_name, debug_file_path)) + logger.info("debug info created on pod %s in path %s", + pod_name, debug_file_path) else: logger.warning( - "Failed to extract debug info name from output - " - "Skipping collecting Redis Enterprise cluster debug info".format(out)) + "Failed to extract debug info name from output - (%s)" + "Skipping collecting Redis Enterprise cluster debug info", out) return # copy package from RS pod output_path = os.path.join(output_dir, debug_file_name) - cmd = "kubectl -n {} cp {}:{} {}".format(namespace, pod_name, debug_file_path, output_path) - rc, out = run_shell_command(cmd) - if rc: - logger.warning("Failed to debug info from pod to output directory".format(out)) + cmd = "kubectl -n {} cp {}:{} {}".format(namespace, + pod_name, + debug_file_path, + output_path) + return_code, out = run_shell_command(cmd) + if return_code: + logger.warning("Failed to copy debug info from pod " + "to output directory, output:%s", out) return logger.info("Collected Redis Enterprise cluster debug package") @@ -133,7 +160,8 @@ def collect_cluster_info(output_dir): """ Prints the output of kubectl cluster-info to a file """ - collect_helper(output_dir, cmd="kubectl cluster-info", file_name="cluster_info", resource_name="cluster-info") + collect_helper(output_dir, cmd="kubectl cluster-info", + file_name="cluster_info", resource_name="cluster-info") def collect_events(namespace, output_dir): @@ -142,44 +170,50 @@ def collect_events(namespace, output_dir): """ # events need -n parameter in kubectl if not namespace: - logger.warning("Cannot collect events without namespace - skipping events collection") + logger.warning("Cannot collect events without namespace - " + "skipping events collection") return cmd = "kubectl get events -n {} -o wide".format(namespace) - collect_helper(output_dir, cmd=cmd, file_name="events", resource_name="events") + collect_helper(output_dir, cmd=cmd, + file_name="events", resource_name="events") def collect_api_resources(namespace, output_dir): """ - Creates file for each of the API resources with the output of kubectl get -o yaml + Creates file for each of the API resources + with the output of kubectl get -o yaml """ logger.info("Collecting API resources:") resources_out = OrderedDict() - for resource in api_resources: + for resource in API_RESOURCES: output = run_kubectl_get_yaml(namespace, resource) if output: resources_out[resource] = output - logger.info(" + {}".format(resource)) + logger.info(" + %s", resource) for entry, out in resources_out.items(): - with open(os.path.join(output_dir, "{}.yaml".format(entry)), "w+") as fp: - fp.write(out) + with open(os.path.join(output_dir, + "{}.yaml".format(entry)), "w+") as file_handle: + file_handle.write(out) def collect_api_resources_description(namespace, output_dir): """ - Creates file for each of the API resources with the output of kubectl describe + Creates file for each of the API resources + with the output of kubectl describe """ logger.info("Collecting API resources description:") resources_out = OrderedDict() - for resource in api_resources: + for resource in API_RESOURCES: output = run_kubectl_describe(namespace, resource) if output: resources_out[resource] = output - logger.info(" + {}".format(resource)) + logger.info(" + %s", resource) for entry, out in resources_out.items(): - with open(os.path.join(output_dir, "{}.txt".format(entry)), "w+") as fp: - fp.write(out) + with open(os.path.join(output_dir, + "{}.txt".format(entry)), "w+") as file_handle: + file_handle.write(out) def collect_pods_logs(namespace, output_dir): @@ -192,45 +226,57 @@ def collect_pods_logs(namespace, output_dir): pods = get_pod_names(namespace) if not pods: - logger.warning("Could not get pods list - skipping pods logs collection") + logger.warning("Could not get pods list - " + "skipping pods logs collection") return for pod in pods: - cmd = "kubectl logs --all-containers=true -n {} {}".format(namespace, pod) - with open(os.path.join(logs_dir, "{}.log".format(pod)), "w+") as fp: - rc, output = run_shell_command(cmd) - fp.write(output) + cmd = "kubectl logs --all-containers=true -n {} {}"\ + .format(namespace, pod) + with open(os.path.join(logs_dir, "{}.log".format(pod)), + "w+") as file_handle: + _, output = run_shell_command(cmd) + file_handle.write(output) - logger.info(" + {}".format(pod)) + logger.info(" + %s", pod) def archive_files(output_dir, output_dir_name): + """ + Create a compressed tar out of the debug file collection + """ + file_name = output_dir + ".tar.gz" with tarfile.open(file_name, "w|gz") as tar: tar.add(output_dir, arcname=output_dir_name) - logger.info("Archived files into {}".format(file_name)) + logger.info("Archived files into %s", file_name) try: shutil.rmtree(output_dir) - except OSError as e: - logger.warning("Failed to delete directory after archiving: %s", e) + except OSError as ex: + logger.warning("Failed to delete directory after archiving: %s", ex) -def get_pod_names(namespace, selector=""): +def get_pods(namespace, selector=""): """ - Returns list of pods names + Returns list of pods """ if selector: selector = '--selector="{}"'.format(selector) cmd = 'kubectl get pod -n {} {} -o json '.format(namespace, selector) - rc, out = run_shell_command(cmd) - if rc: - logger.warning("Failed to get pod names: {}".format(out)) - return - pods_json = json.loads(out) + return_code, out = run_shell_command(cmd) + if return_code: + logger.warning("Failed to get pods: %s", out) + return None + return json.loads(out)['items'] - return [pod['metadata']['name'] for pod in pods_json['items']] + +def get_pod_names(namespace, selector=""): + """ + Returns list of pod names + """ + return [pod['metadata']['name'] for pod in get_pods(namespace, selector)] def get_namespace_from_config(): @@ -239,37 +285,44 @@ def get_namespace_from_config(): """ # find namespace from config file cmd = "kubectl config view -o json" - rc, out = run_shell_command(cmd) - if rc: - return + return_code, out = run_shell_command(cmd) + if return_code: + return None config = json.loads(out) current_context = config.get('current-context') if not current_context: - return + return None for context in config.get('contexts', []): if context['name'] == current_context: if context['context'].get("namespace"): return context['context']["namespace"] break + return None def collect_helper(output_dir, cmd, file_name, resource_name): """ Runs command, write output to file_name, logs the resource_name """ - rc, out = run_shell_command(cmd) - if rc: - logger.warning("Error when running {}: {}".format(cmd, out)) + return_code, out = run_shell_command(cmd) + if return_code: + logger.warning("Error when running %s: %s", cmd, out) return path = os.path.join(output_dir, file_name) - with open(path, "w+") as fp: - fp.write(out) - logger.info("Collected {}".format(resource_name)) + with open(path, "w+") as file_handle: + file_handle.write(out) + logger.info("Collected %s", resource_name) -def native_string(x): - return x if isinstance(x, str) else x.decode('utf-8', 'replace') +def native_string(input_var): + """ + Decode a variable to utf-8 if it is not a string + """ + if isinstance(input_var, str): + return input_var + + return input_var.decode('utf-8', 'replace') def run_kubectl_get_yaml(namespace, resource_type): @@ -277,18 +330,24 @@ def run_kubectl_get_yaml(namespace, resource_type): Runs kubectl get command with yaml format """ cmd = "kubectl get -n {} {} -o yaml".format(namespace, resource_type) - rc, out = run_shell_command(cmd) - if rc == 0: + return_code, out = run_shell_command(cmd) + if return_code == 0: return out - logger.warning("Failed to get {} resource: {}".format(resource_type, out.rstrip())) + logger.warning("Failed to get %s resource: %s", + resource_type, out.rstrip()) + return None def run_shell_command(args): - # to allow timeouts to work in windows, would need to find another mechanism that signal.alarm based + """ + Run a shell command + """ + # to allow timeouts to work in windows, + # would need to find another mechanism that signal.alarm based if sys.platform == 'win32' or timeout == 0: return run_shell_command_regular(args) - else: - return run_shell_command_timeout(args) + + return run_shell_command_timeout(args) def run_shell_command_regular(args): @@ -296,39 +355,59 @@ def run_shell_command_regular(args): Returns a tuple of the shell exit code, output """ try: - output = subprocess.check_output(args, shell=True, stderr=subprocess.STDOUT) + output = subprocess.check_output(args, + shell=True, + stderr=subprocess.STDOUT) except subprocess.CalledProcessError as ex: - logger.warning("Failed in shell command: {}, output: {}".format(args, ex.output)) + logger.warning("Failed in shell command: %s, output: %s", + args, ex.output) return ex.returncode, ex.output return 0, native_string(output) def run_shell_command_timeout(args, cwd=None, shell=True, env=None): - def get_process_children(parent): - pr = subprocess.Popen('ps --no-headers -o pid --ppid %d' % parent, shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = pr.communicate() - return [int(proc) for proc in stdout.split()] + """ + Utility function to run a shell command with a timeout + """ + def get_process_children(parent): + piped_process = subprocess.Popen('ps --no-headers -o pid ' + '--ppid %d' % parent, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, _ = piped_process.communicate() + return [int(piped_process) for proc in stdout.split()] + + # no need for pass here: + # https://github.com/PyCQA/pylint/issues/2616#issuecomment-442738701 + # do not remove the doc string - code would break class Alarm(Exception): - pass + """ + Custom alarm exception + """ def alarm_handler(_, __): raise Alarm - p = subprocess.Popen(args, shell=shell, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) + piped_process = subprocess.Popen(args, + shell=shell, + cwd=cwd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=env) if timeout != 0: signal.signal(signal.SIGALRM, alarm_handler) signal.alarm(timeout) try: - output, _ = p.communicate() + output, _ = piped_process.communicate() # disable alarm after process returns signal.alarm(0) except Alarm: - logger.warning("cmd: %s timed out" % args) - pids = [p.pid] - pids.extend(get_process_children(p.pid)) + logger.warning("cmd: %s timed out", args) + pids = [piped_process.pid] + pids.extend(get_process_children(piped_process.pid)) for pid in pids: # process might have died before getting to this line # so wrap to avoid OSError: no such process @@ -338,7 +417,7 @@ def alarm_handler(_, __): pass return -9, "cmd: %s timed out" % args - return p.returncode, native_string(output) + return piped_process.returncode, native_string(output) def run_kubectl_describe(namespace, resource_type): @@ -346,25 +425,34 @@ def run_kubectl_describe(namespace, resource_type): Runs kubectl describe command """ cmd = "kubectl describe -n {} {}".format(namespace, resource_type) - rc, out = run_shell_command(cmd) - if rc == 0: + return_code, out = run_shell_command(cmd) + if return_code == 0: return out - logger.warning("Failed to describe {} resource: {}".format(resource_type, out)) + logger.warning("Failed to describe %s resource: %s", resource_type, out) + return None if __name__ == "__main__": logger.setLevel(logging.INFO) logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s') - parser = argparse.ArgumentParser(description='Redis Enterprise K8s log collector') + # pylint: disable=locally-disabled, invalid-name + parser = argparse.ArgumentParser(description='Redis Enterprise' + ' K8s log collector') parser.add_argument('-n', '--namespace', action="store", type=str) parser.add_argument('-o', '--output_dir', action="store", type=str) - parser.add_argument('-t', '--timeout', action="store", type=int, default=120, - help="time to wait for external commands to finish execution " - "(default: 120s, specify 0 to not timeout) (Linux only)") - + parser.add_argument('-t', '--timeout', action="store", + type=int, default=120, + help="time to wait for external commands to " + "finish execution " + "(default: 120s, specify 0 to not timeout) " + "(Linux only)") + + # pylint: disable=locally-disabled, invalid-name results = parser.parse_args() + + # pylint: disable=locally-disabled, invalid-name timeout = results.timeout if timeout < 0: logger.error("timeout can't be less than 0") diff --git a/log_collector/pylama.ini b/log_collector/pylama.ini new file mode 100644 index 0000000..768d8e2 --- /dev/null +++ b/log_collector/pylama.ini @@ -0,0 +1,5 @@ +[pylama:pylint] +max_line_length = 120 + +[pylama:pep8] +max_line_length = 120 \ No newline at end of file diff --git a/openshift.bundle.yaml b/openshift.bundle.yaml index 80ed5ca..6dd68bc 100644 --- a/openshift.bundle.yaml +++ b/openshift.bundle.yaml @@ -1,4 +1,20 @@ --- +kind: SecurityContextConstraints +apiVersion: security.openshift.io/v1 +metadata: + name: redis-enterprise-scc +allowPrivilegedContainer: false +allowedCapabilities: + - SYS_RESOURCE +runAsUser: + type: MustRunAs + uid: 1001 +FSGroup: + type: MustRunAs + ranges: 1001,1001 +seLinuxContext: + type: RunAsAny +--- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -124,7 +140,7 @@ spec: serviceAccount: redis-enterprise-operator containers: - name: redis-enterprise-operator - image: redislabs/operator:5.4.10-8.rhel7 + image: redislabs/operator:5.4.14-2.rhel7 securityContext: runAsUser: 1001 command: diff --git a/openshift/operator_rhel.yaml b/openshift/operator_rhel.yaml index 71c0b87..8edabe7 100644 --- a/openshift/operator_rhel.yaml +++ b/openshift/operator_rhel.yaml @@ -15,7 +15,7 @@ spec: serviceAccount: redis-enterprise-operator containers: - name: redis-enterprise-operator - image: redislabs/operator:5.4.10-8.rhel7 + image: redislabs/operator:5.4.14-2.rhel7 securityContext: runAsUser: 1001 command: diff --git a/openshift/redis-enterprise-cluster_rhel.yaml b/openshift/redis-enterprise-cluster_rhel.yaml index 64bac55..772670a 100644 --- a/openshift/redis-enterprise-cluster_rhel.yaml +++ b/openshift/redis-enterprise-cluster_rhel.yaml @@ -19,5 +19,5 @@ spec: redisEnterpriseImageSpec: imagePullPolicy: IfNotPresent repository: redislabs/redis - versionTag: 5.4.10-22.rhel7-openshift + versionTag: 5.4.14-19.rhel7-openshift diff --git a/openshift/with_service_broker_rhel.yaml b/openshift/with_service_broker_rhel.yaml index f4ec656..41d53f5 100644 --- a/openshift/with_service_broker_rhel.yaml +++ b/openshift/with_service_broker_rhel.yaml @@ -11,4 +11,4 @@ spec: redisEnterpriseImageSpec: imagePullPolicy: IfNotPresent repository: redislabs/redis - versionTag: 5.4.10-22.rhel7-openshift + versionTag: 5.4.14-19.rhel7-openshift diff --git a/operator.yaml b/operator.yaml index 4aa364a..aa5a2c3 100644 --- a/operator.yaml +++ b/operator.yaml @@ -1,4 +1,4 @@ -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: redis-enterprise-operator @@ -15,7 +15,8 @@ spec: serviceAccountName: redis-enterprise-operator containers: - name: redis-enterprise-operator - image: redislabs/operator:5.4.10-8 + # Replace this with the built image name + image: redislabs/operator:5.4.14-2 command: - redis-enterprise-operator imagePullPolicy: Always diff --git a/rack_awareness/rack_aware_cluster_role.yaml b/rack_awareness/rack_aware_cluster_role.yaml index 4947a84..0566cec 100644 --- a/rack_awareness/rack_aware_cluster_role.yaml +++ b/rack_awareness/rack_aware_cluster_role.yaml @@ -3,59 +3,7 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: redis-enterprise-operator rules: - - apiGroups: ["rbac.authorization.k8s.io", ""] - resources: ["roles", "serviceaccounts", "rolebindings"] - verbs: ["*"] - - apiGroups: - - app.redislabs.com - resources: - - "*" - verbs: - - "*" - - apiGroups: [""] - resources: ["secrets"] - verbs: ["*"] - - apiGroups: [""] - resources: ["endpoints"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["create"] - - apiGroups: ["apps"] - resources: ["deployments", "statefulsets"] - verbs: ["*"] - - apiGroups: ["policy"] - resources: ["poddisruptionbudgets"] - verbs: ["create", "delete", "get"] - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["create", "delete", "get" , "update", "list", "watch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["create", "delete", "get" , "update"] - # needed for rack awareness - apiGroups: [""] resources: ["nodes"] verbs: ["list", "get", "watch"] - - # needed rbac rules for services controller - - apiGroups: [""] - resources: ["pods"] - verbs: ["get", "watch", "list", "update", "patch"] - - apiGroups: [""] - resources: ["services"] - verbs: ["get", "watch", "list", "update", "patch", "create", "delete"] - - apiGroups: - - route.openshift.io - resources: ["routes", "routes/custom-host"] - verbs: ["*"] - - apiGroups: ["extensions"] - resources: ["podsecuritypolicies"] - resourceNames: - - redis-enterprise-psp - verbs: - - use - - apiGroups: ["extensions"] - resources: ["ingresses"] - verbs: ["*"]