diff --git a/basic-python-flask/files/builds/dev/params b/basic-python-flask/files/builds/dev/params new file mode 100644 index 00000000..20fe21fc --- /dev/null +++ b/basic-python-flask/files/builds/dev/params @@ -0,0 +1,3 @@ +APPLICATION_NAME=flask-rest +NAMESPACE=basic-python-flask-build +SOURCE_REPOSITORY_URL=https://github.com/pabrahamsson/python-flask-rest.git diff --git a/basic-python-flask/files/builds/jenkins-slave-template.yml b/basic-python-flask/files/builds/jenkins-slave-template.yml new file mode 100644 index 00000000..1d758d6c --- /dev/null +++ b/basic-python-flask/files/builds/jenkins-slave-template.yml @@ -0,0 +1,67 @@ +apiVersion: v1 +kind: Template +labels: + template: jenkins-slave +metadata: + annotations: + description: Template for Jenkins slave + iconClass: icon-jenkins + tags: instant-app,jenkins + name: jenkins-slave +objects: +- kind: BuildConfig + apiVersion: v1 + metadata: + labels: + application: ${SLAVE_NAME} + name: ${SLAVE_NAME} + namespace: ${NAMESPACE} + spec: + output: + to: + kind: ImageStreamTag + name: ${SLAVE_NAME}:latest + source: + type: Git + git: + uri: ${SOURCE_REPOSITORY_URL} + ref: ${SOURCE_REPOSITORY_REF} + contextDir: ${CONTEXT_DIR} + strategy: + dockerStrategy: + from: + kind: DockerImage + name: ${JENKINS_IMAGE} + triggers: + - type: ConfigChange +- apiVersion: v1 + kind: ImageStream + metadata: + annotations: + slave-label: python + labels: + application: ${SLAVE_NAME} + role: jenkins-slave + name: ${SLAVE_NAME} + namespace: ${NAMESPACE} +parameters: +- description: The name for the application. + name: SLAVE_NAME + required: true +- description: The namespace to deploy into + name: NAMESPACE + required: true +- description: Git source URL for application + name: SOURCE_REPOSITORY_URL + required: true + value: https://github.com/pabrahamsson/jenkins.git +- description: Git branch/tag reference + name: SOURCE_REPOSITORY_REF + value: master +- description: Path within Git repository to build; empty for root of repository + name: CONTEXT_DIR + value: +- description: The Jenkins source image + name: JENKINS_IMAGE + required: true + value: openshift/jenkins-slave-base-centos7 diff --git a/basic-python-flask/files/builds/jenkins-slave/params b/basic-python-flask/files/builds/jenkins-slave/params new file mode 100644 index 00000000..8e54048b --- /dev/null +++ b/basic-python-flask/files/builds/jenkins-slave/params @@ -0,0 +1,4 @@ +SLAVE_NAME=slave-python +NAMESPACE=basic-python-flask-build +CONTEXT_DIR=slave-python +SOURCE_REPOSITORY_REF=slave-python diff --git a/basic-python-flask/files/builds/template.yml b/basic-python-flask/files/builds/template.yml new file mode 100644 index 00000000..8e7e6f78 --- /dev/null +++ b/basic-python-flask/files/builds/template.yml @@ -0,0 +1,109 @@ +apiVersion: v1 +kind: Template +labels: + template: generic-python-jenkins-pipeline +metadata: + annotations: + description: Application template for Flask applications built using a Jenkins Pipeline + iconClass: icon-python + tags: flask, python, jenkins-ci + version: 1.0.0 + name: generic-python-jenkins-pipeline +objects: +- kind: BuildConfig + apiVersion: v1 + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME}-pipeline + namespace: ${NAMESPACE} + spec: + source: + type: Git + git: + uri: ${SOURCE_REPOSITORY_URL} + ref: ${SOURCE_REPOSITORY_REF} + contextDir: ${CONTEXT_DIR} + triggers: + - type: GitHub + github: + secret: ${GITHUB_WEBHOOK_SECRET} + - type: ConfigChange + strategy: + type: JenkinsPipeline + jenkinsPipelineStrategy: + jenkinsfilePath: ${PIPELINE_SCRIPT} +- kind: BuildConfig + apiVersion: v1 + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + output: + to: + kind: ImageStreamTag + name: ${APPLICATION_NAME}:latest + source: + type: Git + git: + uri: ${SOURCE_REPOSITORY_URL} + ref: ${SOURCE_REPOSITORY_REF} + contextDir: ${CONTEXT_DIR} + strategy: + sourceStrategy: + from: + kind: ImageStreamTag + name: ${IMAGE_STREAM_TAG_NAME} + namespace: ${IMAGE_STREAM_NAMESPACE} + type: Source +- apiVersion: v1 + kind: ImageStream + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} +parameters: +- description: The name for the application. + name: APPLICATION_NAME + required: true + value: flask-rest +- description: The namespace to deploy into + name: NAMESPACE + required: true +- description: Git source URL for application + name: SOURCE_REPOSITORY_URL + required: true + value: https://github.com/redhat-cop/python-flask-rest.git +- description: Git branch/tag reference + name: SOURCE_REPOSITORY_REF + value: master +- description: Path within Git repository to build; empty for root of repository + name: CONTEXT_DIR + value: +- description: Path within Git repository pointing to the pipeline run script + name: PIPELINE_SCRIPT + value: Jenkinsfile +- description: Github trigger secret + from: '[a-zA-Z0-9]{8}' + generate: expression + name: GITHUB_WEBHOOK_SECRET + required: true +- description: Generic build trigger secret + from: '[a-zA-Z0-9]{8}' + generate: expression + name: GENERIC_WEBHOOK_SECRET + required: true +- description: Namespace in which the ImageStreams for Red Hat Middleware images are + installed. These ImageStreams are normally installed in the openshift namespace. + You should only need to modify this if you've installed the ImageStreams in a + different namespace/project. + name: IMAGE_STREAM_NAMESPACE + required: true + value: openshift +- description: Image stream tag for the image you'd like to use to build the application + name: IMAGE_STREAM_TAG_NAME + required: true + value: python:3.5 diff --git a/basic-python-flask/files/deployments/build/params b/basic-python-flask/files/deployments/build/params new file mode 100644 index 00000000..c226f6bb --- /dev/null +++ b/basic-python-flask/files/deployments/build/params @@ -0,0 +1,2 @@ +INSTALL_PLUGINS=cobertura:1.12,sonar:2.6.1 +MEMORY_LIMIT=512Mi diff --git a/basic-python-flask/files/deployments/dev/params b/basic-python-flask/files/deployments/dev/params new file mode 100644 index 00000000..ae8a2f00 --- /dev/null +++ b/basic-python-flask/files/deployments/dev/params @@ -0,0 +1,4 @@ +APPLICATION_NAME=flask-rest +NAMESPACE=basic-python-flask-dev +SA_NAMESPACE=basic-python-flask-build +READINESS_RESPONSE=status.:..success diff --git a/basic-python-flask/files/deployments/jenkins.yml b/basic-python-flask/files/deployments/jenkins.yml new file mode 100644 index 00000000..e17caaf1 --- /dev/null +++ b/basic-python-flask/files/deployments/jenkins.yml @@ -0,0 +1,195 @@ +apiVersion: v1 +kind: Template +labels: + app: jenkins-ephemeral + template: jenkins-ephemeral-template +metadata: + annotations: + description: |- + Jenkins service, without persistent storage. + + WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing. + iconClass: icon-jenkins + openshift.io/display-name: Jenkins (Ephemeral) + openshift.io/documentation-url: https://docs.openshift.org/latest/using_images/other_images/jenkins.html + openshift.io/long-description: This template deploys a Jenkins server capable + of managing OpenShift Pipeline builds and supporting OpenShift-based oauth login. The + Jenkins configuration is stored in non-persistent storage, so this configuration + should be used for experimental purposes only. + openshift.io/provider-display-name: Red Hat, Inc. + openshift.io/support-url: https://access.redhat.com + tags: instant-app,jenkins + name: jenkins-ephemeral +objects: +- apiVersion: v1 + kind: Route + metadata: + annotations: + template.openshift.io/expose-uri: http://{.spec.host}{.spec.path} + name: ${JENKINS_SERVICE_NAME} + spec: + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: ${JENKINS_SERVICE_NAME} +- apiVersion: v1 + kind: DeploymentConfig + metadata: + annotations: + template.alpha.openshift.io/wait-for-ready: "true" + name: ${JENKINS_SERVICE_NAME} + spec: + replicas: 1 + selector: + name: ${JENKINS_SERVICE_NAME} + strategy: + type: Recreate + template: + metadata: + labels: + name: ${JENKINS_SERVICE_NAME} + spec: + containers: + - capabilities: {} + env: + - name: OPENSHIFT_ENABLE_OAUTH + value: ${ENABLE_OAUTH} + - name: OPENSHIFT_ENABLE_REDIRECT_PROMPT + value: "true" + - name: KUBERNETES_MASTER + value: https://kubernetes.default:443 + - name: KUBERNETES_TRUST_CERTIFICATES + value: "true" + - name: JENKINS_SERVICE_NAME + value: ${JENKINS_SERVICE_NAME} + - name: JNLP_SERVICE_NAME + value: ${JNLP_SERVICE_NAME} + - name: INSTALL_PLUGINS + value: ${INSTALL_PLUGINS} + image: ' ' + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 30 + httpGet: + path: /login + port: 8080 + initialDelaySeconds: 420 + timeoutSeconds: 3 + name: jenkins + readinessProbe: + httpGet: + path: /login + port: 8080 + initialDelaySeconds: 3 + timeoutSeconds: 3 + resources: + limits: + memory: ${MEMORY_LIMIT} + securityContext: + capabilities: {} + privileged: false + terminationMessagePath: /dev/termination-log + volumeMounts: + - mountPath: /var/lib/jenkins + name: ${JENKINS_SERVICE_NAME}-data + dnsPolicy: ClusterFirst + restartPolicy: Always + serviceAccountName: ${JENKINS_SERVICE_NAME} + volumes: + - emptyDir: + medium: "" + name: ${JENKINS_SERVICE_NAME}-data + triggers: + - imageChangeParams: + automatic: true + containerNames: + - jenkins + from: + kind: ImageStreamTag + name: ${JENKINS_IMAGE_STREAM_TAG} + namespace: ${NAMESPACE} + lastTriggeredImage: "" + type: ImageChange + - type: ConfigChange +- apiVersion: v1 + kind: ServiceAccount + metadata: + annotations: + serviceaccounts.openshift.io/oauth-redirectreference.jenkins: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"${JENKINS_SERVICE_NAME}"}}' + name: ${JENKINS_SERVICE_NAME} +- apiVersion: v1 + groupNames: null + kind: RoleBinding + metadata: + name: ${JENKINS_SERVICE_NAME}_edit + roleRef: + name: edit + subjects: + - kind: ServiceAccount + name: ${JENKINS_SERVICE_NAME} +- apiVersion: v1 + kind: Service + metadata: + name: ${JNLP_SERVICE_NAME} + spec: + ports: + - name: agent + nodePort: 0 + port: 50000 + protocol: TCP + targetPort: 50000 + selector: + name: ${JENKINS_SERVICE_NAME} + sessionAffinity: None + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + annotations: + service.alpha.openshift.io/dependencies: '[{"name": "${JNLP_SERVICE_NAME}", + "namespace": "", "kind": "Service"}]' + service.openshift.io/infrastructure: "true" + name: ${JENKINS_SERVICE_NAME} + spec: + ports: + - name: web + nodePort: 0 + port: 80 + protocol: TCP + targetPort: 8080 + selector: + name: ${JENKINS_SERVICE_NAME} + sessionAffinity: None + type: ClusterIP +parameters: +- description: The name of the OpenShift Service exposed for the Jenkins container. + displayName: Jenkins Service Name + name: JENKINS_SERVICE_NAME + value: jenkins +- description: The name of the service used for master/slave communication. + displayName: Jenkins JNLP Service Name + name: JNLP_SERVICE_NAME + value: jenkins-jnlp +- description: Whether to enable OAuth OpenShift integration. If false, the static + account 'admin' will be initialized with the password 'password'. + displayName: Enable OAuth in Jenkins + name: ENABLE_OAUTH + value: "true" +- description: Maximum amount of memory the container can use. + displayName: Memory Limit + name: MEMORY_LIMIT + value: 512Mi +- description: The OpenShift Namespace where the Jenkins ImageStream resides. + displayName: Jenkins ImageStream Namespace + name: NAMESPACE + value: openshift +- description: Name of the ImageStreamTag to be used for the Jenkins image. + displayName: Jenkins ImageStreamTag + name: JENKINS_IMAGE_STREAM_TAG + value: jenkins:latest +- description: Comma-separated list of additional plugins to install on startup. The format of each plugin spec is 'plugin-id:version' + displayName: Additional Jenkins plugins to install + name: INSTALL_PLUGINS + value: '' diff --git a/basic-python-flask/files/deployments/postgresql/params b/basic-python-flask/files/deployments/postgresql/params new file mode 100644 index 00000000..1867b6b8 --- /dev/null +++ b/basic-python-flask/files/deployments/postgresql/params @@ -0,0 +1,4 @@ +POSTGRESQL_DATABASE=sonar +VOLUME_CAPACITY=5 +POSTGRESQL_PASSWORD=sonar +POSTGRESQL_USER=sonar diff --git a/basic-python-flask/files/deployments/prod/params b/basic-python-flask/files/deployments/prod/params new file mode 100644 index 00000000..b306a524 --- /dev/null +++ b/basic-python-flask/files/deployments/prod/params @@ -0,0 +1,4 @@ +APPLICATION_NAME=flask-rest +NAMESPACE=basic-python-flask-prod +SA_NAMESPACE=basic-python-flask-build +READINESS_RESPONSE=status.:..success diff --git a/basic-python-flask/files/deployments/sonar/params b/basic-python-flask/files/deployments/sonar/params new file mode 100644 index 00000000..909dba70 --- /dev/null +++ b/basic-python-flask/files/deployments/sonar/params @@ -0,0 +1,9 @@ +MEMORY_LIMIT=1Gi +VOLUME_CAPACITY=2Gi +MEMORY_LIMIT=2Gi +CPU_LIMIT=1 +JDBC_URL=jdbc:postgresql://postgresql:5432/sonar +JDBC_USER=sonar +JDBC_PASSWORD=sonar +SOURCE_REPOSITORY_URL=https://github.com/rht-labs/labs-ci-cd +SOURCE_REPOSITORY_CONTEXT_DIR=docker/sonarqube diff --git a/basic-python-flask/files/deployments/stage/params b/basic-python-flask/files/deployments/stage/params new file mode 100644 index 00000000..52f24087 --- /dev/null +++ b/basic-python-flask/files/deployments/stage/params @@ -0,0 +1,4 @@ +APPLICATION_NAME=flask-rest +NAMESPACE=basic-python-flask-stage +SA_NAMESPACE=basic-python-flask-build +READINESS_RESPONSE=status.:..success diff --git a/basic-python-flask/files/deployments/template.yml b/basic-python-flask/files/deployments/template.yml new file mode 100644 index 00000000..c276e76f --- /dev/null +++ b/basic-python-flask/files/deployments/template.yml @@ -0,0 +1,137 @@ +apiVersion: v1 +kind: Template +labels: + template: basic-python-flask +metadata: + annotations: + description: Application template for Flask applications built using a Jenkins Pipeline + iconClass: icon-python + tags: python, flask + version: 1.0.0 + name: basic-python-fask +objects: +- apiVersion: v1 + kind: Service + metadata: + annotations: + description: The web server's http port. + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + ports: + - port: 8080 + targetPort: 8080 + selector: + deploymentConfig: ${APPLICATION_NAME} +- apiVersion: v1 + id: ${APPLICATION_NAME}-http + kind: Route + metadata: + annotations: + description: Route for application's http service. + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + host: ${HOSTNAME_HTTP} + to: + name: ${APPLICATION_NAME} +- apiVersion: v1 + kind: ImageStream + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} +- apiVersion: v1 + kind: DeploymentConfig + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + replicas: 1 + selector: + deploymentConfig: ${APPLICATION_NAME} + strategy: + type: Rolling + template: + metadata: + labels: + application: ${APPLICATION_NAME} + deploymentConfig: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + spec: + containers: + - image: ${APPLICATION_NAME} + imagePullPolicy: Always + name: ${APPLICATION_NAME} + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + exec: + command: + - /bin/bash + - -c + - curl -s 'http://localhost:8080${READINESS_PATH}' + |grep -iq '${READINESS_RESPONSE}' + terminationGracePeriodSeconds: 60 + triggers: + - imageChangeParams: + automatic: true + containerNames: + - ${APPLICATION_NAME} + from: + kind: ImageStreamTag + name: ${APPLICATION_NAME}:latest + type: ImageChange + - type: ConfigChange +- apiVersion: v1 + groupNames: null + kind: RoleBinding + metadata: + creationTimestamp: null + labels: + template: basic-python-flask-template + name: jenkins_edit + namespace: ${NAMESPACE} + roleRef: + name: edit + subjects: + - kind: ServiceAccount + name: ${SA_NAME} + namespace: ${SA_NAMESPACE} + userNames: + - system:serviceaccount:${SA_NAMESPACE}:${SA_NAME} +parameters: +- description: The name for the application. + name: APPLICATION_NAME + required: true + value: flask-rest +- description: The namespace to deploy into + name: NAMESPACE + required: true +- description: Name of a service account that can deploy to this project + name: SA_NAME + required: true + value: jenkins +- description: Namespace of service account that can deploy to this project + name: SA_NAMESPACE + required: true +- description: 'Custom hostname for http service route. Leave blank for default hostname, + e.g.: -.' + name: HOSTNAME_HTTP +- description: 'URI to check for app health' + name: READINESS_PATH + required: true + value: '/health' +- description: 'String value expected back from readiness check' + name: READINESS_RESPONSE + required: true + value: 'Hello World!' diff --git a/basic-python-flask/files/imagestreams/imagestreams.yml b/basic-python-flask/files/imagestreams/imagestreams.yml new file mode 100644 index 00000000..46d4a014 --- /dev/null +++ b/basic-python-flask/files/imagestreams/imagestreams.yml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: ImageStream +metadata: + annotations: + openshift.io/image.dockerRepositoryCheck: 2017-12-14T21:50:52Z + creationTimestamp: null + generation: 3 + name: jenkins-slave-python-centos7 +spec: + lookupPolicy: + local: false + tags: + - annotations: + role: jenkins-slave + slave-label: python + from: + kind: DockerImage + name: docker.io/pabrahamsson/jenkins-slave-python-centos7:latest + importPolicy: {} + name: latest + referencePolicy: + type: Source + - annotations: + role: jenkins-slave + slave-label: python + from: + kind: DockerImage + name: docker.io/pabrahamsson/jenkins-slave-python-centos7:v3.9 + importPolicy: {} + name: v3.9 + referencePolicy: + type: Source + - annotations: + role: jenkins-slave + slave-label: python + from: + kind: DockerImage + name: docker.io/pabrahamsson/jenkins-slave-python-centos7:v3.7 + importPolicy: {} + name: v3.7 + referencePolicy: + type: Source diff --git a/basic-python-flask/files/projects/projects.yml b/basic-python-flask/files/projects/projects.yml new file mode 100644 index 00000000..4c8f80b6 --- /dev/null +++ b/basic-python-flask/files/projects/projects.yml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: List +items: +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: basic-python-flask-dev + creationTimestamp: null + displayName: Dev - Python Flask App +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: basic-python-flask-stage + creationTimestamp: null + displayName: Staging - Python Flask App +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: basic-python-flask-prod + creationTimestamp: null + displayName: Prod - Python Flask App +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: basic-python-flask-build + creationTimestam: null + displayName: Build - Jenkins is here diff --git a/basic-python-flask/inventory/group_vars/all.yml b/basic-python-flask/inventory/group_vars/all.yml new file mode 100644 index 00000000..1cab57ca --- /dev/null +++ b/basic-python-flask/inventory/group_vars/all.yml @@ -0,0 +1,40 @@ +--- +openshift_cluster_content: +- object: projectrequest + content: + - name: basic-python-flask-spaces + file: "{{ inventory_dir }}/../files/projects/projects.yml" + file_action: create +- object: builds + content: + - name: jenkins-slave-python + template: "{{ inventory_dir }}/../files/builds/jenkins-slave-template.yml" + params: "{{ inventory_dir }}/../files/builds/jenkins-slave/params" +- object: deployments + content: + - name: postgresql + namespace: basic-python-flask-build + template: openshift//postgresql-persistent + params: "{{ inventory_dir }}/../files/deployments/postgresql/params" + - name: sonarqube + namespace: basic-python-flask-build + template: https://raw.githubusercontent.com/rht-labs/labs-ci-cd/master/openshift-templates/sonarqube/template.json + params: "{{ inventory_dir }}/../files/deployments/sonar/params" + - name: jenkins + namespace: basic-python-flask-build + template: "{{ inventory_dir }}/../files/deployments/jenkins.yml" + params: "{{ inventory_dir }}/../files/deployments/build/params" + - name: basic-python-flask-dev + template: "{{ inventory_dir }}/../files/deployments/template.yml" + params: "{{ inventory_dir }}/../files/deployments/dev/params" + - name: basic-python-flask-stage + template: "{{ inventory_dir }}/../files/deployments/template.yml" + params: "{{ inventory_dir }}/../files/deployments/stage/params" + - name: basic-python-flask-prod + template: "{{ inventory_dir }}/../files/deployments/template.yml" + params: "{{ inventory_dir }}/../files/deployments/prod/params" +- object: builds + content: + - name: jenkins + template: "{{ inventory_dir }}/../files/builds/template.yml" + params: "{{ inventory_dir }}/../files/builds/dev/params" diff --git a/basic-python-flask/inventory/hosts b/basic-python-flask/inventory/hosts new file mode 100644 index 00000000..05c07035 --- /dev/null +++ b/basic-python-flask/inventory/hosts @@ -0,0 +1,2 @@ +[seed-hosts] +localhost