Skip to content

Commit b5bdfaf

Browse files
Improve commit checks and code formatting (#26)
- update github actions: - Separate lint, build, test action - Add coverage report in text to PR - fix: reduce number of flake8 warnings - fix formating - remove unused code - fix: enable warnings and improve logging - move to codeql v2 Signed-off-by: Ricky Moorhouse <[email protected]>
1 parent c93703f commit b5bdfaf

File tree

9 files changed

+149
-85
lines changed

9 files changed

+149
-85
lines changed

.coveragerc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[run]
2+
relative_files = true

.github/workflows/build.yml

Lines changed: 0 additions & 52 deletions
This file was deleted.

.github/workflows/codeql-analysis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
5151
# If this step fails, then you should remove it and run the build manually (see below)
5252
- name: Autobuild
53-
uses: github/codeql-action/autobuild@v1
53+
uses: github/codeql-action/autobuild@v2
5454

5555
# ℹ️ Command-line programs to run using the OS shell.
5656
# 📚 https://git.io/JvXDl

.github/workflows/coverage.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# .github/workflows/coverage.yml
2+
name: Post coverage comment
3+
4+
on:
5+
workflow_run:
6+
workflows: ["CI"]
7+
types:
8+
- completed
9+
10+
jobs:
11+
test:
12+
name: Run tests & display coverage
13+
runs-on: ubuntu-latest
14+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
15+
steps:
16+
# DO NOT run actions/checkout@v2 here, for securitity reasons
17+
# For details, refer to https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
18+
- name: Post comment
19+
uses: ewjoachim/python-coverage-comment-action@v2
20+
with:
21+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }}
23+
# Update those if you changed the default values:
24+
# COMMENT_ARTIFACT_NAME: python-coverage-comment-action
25+
# COMMENT_FILENAME: python-coverage-comment-action.txt
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# This workflow will install Python dependencies, run tests and lint with a single version of Python
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3+
4+
name: Build and publish
5+
6+
on:
7+
push:
8+
# Publish `main` as Docker `latest` image.
9+
branches:
10+
- main
11+
# Publish `v1.2.3` tags as releases.
12+
tags:
13+
- v*
14+
15+
pull_request:
16+
branches: [ main ]
17+
18+
env:
19+
IMAGE_NAME: ghcr.io/ibm/apiconnect-trawler/trawler
20+
21+
jobs:
22+
test:
23+
runs-on: ubuntu-latest
24+
25+
steps:
26+
- uses: actions/checkout@v2
27+
- name: Set up Python 3.10
28+
uses: actions/setup-python@v2
29+
with:
30+
python-version: "3.10"
31+
- name: Install dependencies
32+
run: |
33+
python -m pip install --upgrade pip
34+
pip install flake8 pytest
35+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
36+
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
37+
- name: Lint with flake8
38+
run: |
39+
# stop the build if there are Python syntax errors or undefined names
40+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
41+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
42+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
43+
- name: Test with pytest
44+
run: |
45+
SECRETS=test-assets coverage run --source . -m py.test -Werror -p no:unraisableexception
46+
coverage report
47+
48+
# Push image to GitHub Packages.
49+
# See also https://docs.docker.com/docker-hub/builds/
50+
publish:
51+
runs-on: ubuntu-latest
52+
if: github.event_name == 'push'
53+
54+
steps:
55+
- name: Clone the repository
56+
uses: actions/checkout@v2
57+
58+
- name: Buildah Action
59+
id: build-image
60+
uses: redhat-actions/buildah-build@v2
61+
with:
62+
image: ${{ env.IMAGE_NAME }}
63+
tags: latest ${{ github.ref_name }}
64+
containerfiles: |
65+
./Containerfile
66+
67+
- name: Log in to the GitHub Container registry
68+
uses: redhat-actions/podman-login@v1
69+
with:
70+
registry: "ghcr.io"
71+
username: ${{ github.actor }}
72+
password: ${{ secrets.CR_PAT }}
73+
74+
- name: Push to GitHub Container Repository
75+
id: push-to-ghcr
76+
uses: redhat-actions/push-to-registry@v2
77+
with:
78+
registry: "ghcr.io"
79+
image: ${{ steps.build-image.outputs.image }}
80+
tags: latest ${{ github.ref_name }}

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"python.linting.pylamaEnabled": false,
3+
"python.linting.pylintEnabled": true,
4+
"python.linting.enabled": true,
5+
"git.alwaysSignOff": true
6+
}

analytics_net.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ def __init__(self, config, trawler):
3939
self.find_hostname_and_certs()
4040
else:
4141
self.find_hostname_and_certs()
42-
logger.trace("Hostname is %s", self.hostname)
43-
logger.trace("Certificate file is %s", self.certificates.name)
4442

4543
def load_certs_from_secret(self, v1, secret_name):
4644
# Get certificates to communicate with analytics
@@ -110,6 +108,7 @@ def find_hostname_and_certs(self):
110108
if cert:
111109
combined = key + "\n".encode() + cert
112110
self.certificates = tempfile.NamedTemporaryFile('w', delete=False)
111+
logger.trace("Certificate file is %s", self.certificates.name)
113112
with self.certificates as certfile:
114113
certfile.write(combined.decode())
115114

manager_net.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def find_hostname(self):
9898
if self.use_kubeconfig:
9999
logger.info("Using KUBECONFIG")
100100
config.load_kube_config()
101-
netv1 = client.NetworkingV1Api()
102-
ingresslist = netv1.list_namespaced_ingress(namespace=self.namespace)
101+
v1 = client.NetworkV1Api()
102+
ingresslist = v1.list_namespaced_ingress(namespace=self.namespace)
103103
for ing in ingresslist.items:
104104
if ing.metadata.name.endswith('apiconnect-api') or ing.metadata.name.endswith('platform-api'):
105105
logger.info("Identified ingress host: {}".format(ing.spec.rules[0].host))

trawler.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
#!/usr/bin/python3
2+
""" Main trawler application """
23

34
import os
45
import time
5-
import alog
66
import threading
7-
import yaml
7+
import ssl
8+
import alog
89
import click
10+
from prometheus_client import start_http_server, Gauge, Counter, make_wsgi_app
11+
import yaml
912
from certs_net import CertsNet
1013
from apiconnect_net import APIConnectNet
1114
from datapower_net import DataPowerNet
1215
from manager_net import ManagerNet
1316
from analytics_net import AnalyticsNet
14-
from watch_pods import Watcher
15-
from prometheus_client import start_http_server
1617
import metrics_graphite
17-
from prometheus_client import Gauge, Counter
1818

1919

2020
logger = alog.use_channel("trawler")
@@ -67,24 +67,24 @@ def __init__(self, config_file=None):
6767
# Check for KUBERNETES_SERVICE_HOST to determine if running within kubernetes
6868
if os.getenv('KUBERNETES_SERVICE_HOST'):
6969
self.use_kubeconfig = False
70-
self.watcher = Watcher()
7170

7271
def read_secret(self, key):
7372
""" Helper function read secrets from mounted k8s secrets """
7473
try:
75-
with open("{}/{}".format(self.secrets_path, key), 'r') as secret:
74+
with open("{}/{}".format(self.secrets_path, key), 'r', encoding='utf-8') as secret:
7675
value = secret.read().rstrip()
7776
return value
78-
except FileNotFoundError as e:
79-
logger.exception(e)
77+
except FileNotFoundError as not_found_exception:
78+
logger.exception(not_found_exception)
8079
return None
8180

8281
def load_config(self, config_file):
82+
""" Load trawler config """
8383
try:
84-
with open(config_file, 'r') as config_yaml:
84+
with open(config_file, 'r', encoding='utf-8') as config_yaml:
8585
self.config = yaml.safe_load(config_yaml)
86-
except FileNotFoundError as e:
87-
logger.exception(e)
86+
except FileNotFoundError as not_found_exception:
87+
logger.exception(not_found_exception)
8888
exit(2)
8989

9090
def set_gauge(self, component, target_name, value, pod_name=None, labels=None):
@@ -95,14 +95,15 @@ def set_gauge(self, component, target_name, value, pod_name=None, labels=None):
9595
labels['pod'] = pod_name
9696
if 'labels' in self.config['prometheus']:
9797
labels = {**self.config['prometheus']['labels'], **labels}
98-
logger.debug("Entering set_gauge - params: ({}, {}, {}, {})".format(component, target_name, value, pod_name))
98+
logger.debug("Entering set_gauge - params: (%s, %s, %s, %s)",
99+
component, target_name, value, pod_name)
99100
logger.debug(labels)
100-
if type(value) is float or type(value) is int:
101+
if isinstance(value, (float, int)):
101102
target_name = target_name.replace('-', '_')
102103
if self.config['prometheus']['enabled']:
103104
prometheus_target = "{}_{}".format(component, target_name.replace('.', '_'))
104105
if prometheus_target not in self.gauges:
105-
logger.info("Creating gauge {}".format(prometheus_target))
106+
logger.info("Creating gauge %s", prometheus_target)
106107
if labels:
107108
self.gauges[prometheus_target] = Gauge(
108109
prometheus_target,
@@ -136,14 +137,15 @@ def inc_counter(self, component, target_name, value, pod_name=None, labels=None)
136137
labels['pod'] = pod_name
137138
if 'labels' in self.config['prometheus']:
138139
labels = {**self.config['prometheus']['labels'], **labels}
139-
logger.debug("Entering inc_counter - params: ({}, {}, {}, {})".format(component, target_name, value, pod_name))
140+
logger.debug("Entering inc_counter - params: (%s, %s, %s, %s)",
141+
component, target_name, value, pod_name)
140142
logger.debug(labels)
141-
if type(value) is float or type(value) is int:
143+
if isinstance(value, (float, int)):
142144
target_name = target_name.replace('-', '_')
143145
if self.config['prometheus']['enabled']:
144146
prometheus_target = "{}_{}".format(component, target_name.replace('.', '_'))
145147
if prometheus_target not in self.gauges:
146-
logger.info("Creating counter {}".format(prometheus_target))
148+
logger.info("Creating counter %s", prometheus_target)
147149
if labels:
148150
self.gauges[prometheus_target] = Counter(
149151
prometheus_target,
@@ -166,28 +168,30 @@ def inc_counter(self, component, target_name, value, pod_name=None, labels=None)
166168
metric_name = "{}.{}".format(component, target_name)
167169
self.graphite.stage(metric_name, value)
168170

171+
def is_enabled(self, net_name):
172+
""" is net in config and enabled """
173+
if net_name in self.config['nets']:
174+
if self.config['nets']['certs'].get('enabled', True):
175+
return True
176+
return False
177+
169178
@alog.timed_function(logger.trace)
170179
def trawl_metrics(self):
171180
""" Main loop to trawl for metrics """
172181
# Initialise
173182
logger.info("Laying nets...")
174183
nets = []
175-
if 'certs' in self.config['nets'] and self.config['nets']['certs'].get('enabled', True):
184+
if self.is_enabled('certs'):
176185
nets.append(CertsNet(self.config['nets']['certs'], self))
177-
if 'apiconnect' in self.config['nets'] and self.config['nets']['apiconnect'].get('enabled', True):
186+
if self.is_enabled('apiconnect'):
178187
nets.append(APIConnectNet(self.config['nets']['apiconnect'], self))
179-
if 'datapower' in self.config['nets'] and self.config['nets']['datapower'].get('enabled', True):
188+
if self.is_enabled('datapower'):
180189
nets.append(DataPowerNet(self.config['nets']['datapower'], self))
181-
if 'manager' in self.config['nets'] and self.config['nets']['manager'].get('enabled', True):
190+
if self.is_enabled('manager'):
182191
nets.append(ManagerNet(self.config['nets']['manager'], self))
183-
if 'analytics' in self.config['nets'] and self.config['nets']['analytics'].get('enabled', True):
192+
if self.is_enabled('analytics'):
184193
nets.append(AnalyticsNet(self.config['nets']['analytics'], self))
185194

186-
# Start thread to watch if needed (nets need to call watcher.register)
187-
if self.watcher.enabled:
188-
watchThread = threading.Thread(target=self.watcher.watch_pods, daemon=True)
189-
watchThread.start()
190-
191195
while True:
192196
logger.info("Trawling for metrics...")
193197
for net in nets:

0 commit comments

Comments
 (0)