mirror of https://github.com/apache/cassandra
118 lines
5.0 KiB
Bash
Executable File
118 lines
5.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
#
|
|
# Validates the CI declarations under .jenkins/ without deploying anything:
|
|
# - the Jenkinsfile parses as groovy
|
|
# - jenkins-deployment.yaml renders through the jenkins helm chart
|
|
# - the yaml embedded in it (agent pod templates, JCasC config scripts) parses
|
|
#
|
|
# Requires: helm, python3 with pyyaml, and either groovy or docker.
|
|
# Run from anywhere: .jenkins/k8s/jenkins-test.sh
|
|
|
|
set -e
|
|
|
|
CASSANDRA_DIR="$(cd "$(dirname "$0")/../.." > /dev/null && pwd)"
|
|
JENKINS_DIR="${CASSANDRA_DIR}/.jenkins"
|
|
status=0
|
|
|
|
command -v helm > /dev/null || { echo "helm must be installed and in the PATH"; exit 1; }
|
|
command -v python3 > /dev/null || { echo "python3 must be installed and in the PATH"; exit 1; }
|
|
python3 -c "import yaml" 2> /dev/null || { echo "python3 pyyaml must be installed: pip install pyyaml"; exit 1; }
|
|
|
|
echo "== Jenkinsfile groovy syntax"
|
|
# Phases.CONVERSION parses and builds the AST without resolving the pipeline DSL or @NonCPS,
|
|
# neither of which exist outside a jenkins controller
|
|
syntax_check_dir="$(mktemp -d)"
|
|
syntax_check="${syntax_check_dir}/syntax-check.groovy"
|
|
# mktemp gives 0700, which the unprivileged user inside the groovy image cannot traverse
|
|
chmod 755 "${syntax_check_dir}"
|
|
cat > "${syntax_check}" << 'EOF'
|
|
import org.codehaus.groovy.control.CompilationUnit
|
|
import org.codehaus.groovy.control.Phases
|
|
|
|
def cu = new CompilationUnit()
|
|
args.each { cu.addSource(new File(it)) }
|
|
cu.compile(Phases.CONVERSION)
|
|
println " ${args.join(', ')} parses"
|
|
EOF
|
|
if command -v groovy > /dev/null ; then
|
|
groovy "${syntax_check}" "${JENKINS_DIR}/Jenkinsfile" || status=1
|
|
elif command -v docker > /dev/null ; then
|
|
# absolute paths, the image's working directory is not where the script was mounted
|
|
docker run --rm -v "${syntax_check_dir}:/check:ro" -v "${JENKINS_DIR}:/jenkins:ro" \
|
|
groovy:4.0-jdk17 groovy /check/syntax-check.groovy /jenkins/Jenkinsfile || status=1
|
|
else
|
|
echo " SKIPPED: neither groovy nor docker found"
|
|
fi
|
|
|
|
echo "== jenkins-deployment.yaml renders through the helm chart"
|
|
helm repo add jenkins https://charts.jenkins.io > /dev/null
|
|
helm repo update > /dev/null
|
|
# --namespace and a release name only so the chart's templates have something to interpolate
|
|
helm template cassius jenkins/jenkins --namespace default -f "${JENKINS_DIR}/k8s/jenkins-deployment.yaml" > /dev/null \
|
|
&& echo " jenkins-deployment.yaml renders" || status=1
|
|
|
|
echo "== yaml embedded in jenkins-deployment.yaml"
|
|
python3 - "${JENKINS_DIR}/k8s" << 'EOF' || status=1
|
|
import sys, yaml
|
|
from pathlib import Path
|
|
|
|
k8s_dir = Path(sys.argv[1])
|
|
errors = 0
|
|
|
|
for path in sorted(k8s_dir.glob("*.yaml")):
|
|
try:
|
|
values = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
except yaml.YAMLError as error:
|
|
print(f" INVALID {path.name}: {error}")
|
|
errors += 1
|
|
continue
|
|
print(f" {path.name} parses")
|
|
|
|
# the values in these two maps are themselves yaml documents, and a chart never validates them —
|
|
# a misindented pod template reaches the kubernetes plugin and silently loses its agents
|
|
for keys in (("agent", "podTemplates"), ("controller", "JCasC", "configScripts")):
|
|
embedded = values
|
|
for key in keys:
|
|
embedded = embedded.get(key, {}) if isinstance(embedded, dict) else {}
|
|
for name, document in (embedded or {}).items():
|
|
location = f"{path.name} {'.'.join(keys)}.{name}"
|
|
try:
|
|
parsed = yaml.safe_load(document)
|
|
except yaml.YAMLError as error:
|
|
print(f" INVALID {location}: {error}")
|
|
errors += 1
|
|
continue
|
|
print(f" {location} parses")
|
|
# each pod template may carry a raw kubernetes pod spec in a nested `yaml` key
|
|
for template in parsed if isinstance(parsed, list) else []:
|
|
if isinstance(template, dict) and "yaml" in template:
|
|
try:
|
|
yaml.safe_load(template["yaml"])
|
|
except yaml.YAMLError as error:
|
|
print(f" INVALID {location}.yaml: {error}")
|
|
errors += 1
|
|
else:
|
|
print(f" {location}.yaml parses")
|
|
|
|
sys.exit(1 if errors else 0)
|
|
EOF
|
|
|
|
[ 0 -eq ${status} ] && echo "== all .jenkins/ checks passed" || echo "== FAILED"
|
|
exit ${status}
|