4 changed files with 356 additions and 5 deletions
@ -0,0 +1,216 @@ |
|||||
|
#!groovy |
||||
|
|
||||
|
library identifier: '3scale-toolbox-jenkins@openapi3', |
||||
|
retriever: modernSCM([$class: 'GitSCMSource', |
||||
|
remote: 'https://github.com/nmasse-itix/3scale-toolbox-jenkins.git', |
||||
|
traits: [[$class: 'jenkins.plugins.git.traits.BranchDiscoveryTrait']]]) |
||||
|
|
||||
|
def service = null |
||||
|
|
||||
|
node("maven") { |
||||
|
stage('Checkout Source') { |
||||
|
checkout scm |
||||
|
//git url: "https://github.com/nmasse-itix/library-api.git" |
||||
|
} |
||||
|
|
||||
|
stage('Pre-requisites') { |
||||
|
if (! fileExists('openapi.json')) { |
||||
|
|
||||
|
echo """ |
||||
|
There is no OpenAPI Specification file! |
||||
|
""" |
||||
|
|
||||
|
error("Nothing to deploy!") |
||||
|
} |
||||
|
|
||||
|
// Install pre-requisites |
||||
|
sh """ |
||||
|
curl -L -o /tmp/jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 |
||||
|
chmod 755 /tmp/jq |
||||
|
""" |
||||
|
} |
||||
|
|
||||
|
stage("Deploy API in Dev") { |
||||
|
// Prepare |
||||
|
service = toolbox.prepareThreescaleService( |
||||
|
openapi: [filename: "openapi.json" ], |
||||
|
environment: [ baseSystemName: "library", |
||||
|
environmentName: "dev", |
||||
|
oidcIssuerEndpoint: params.OIDC_ISSUER_ENDPOINT, |
||||
|
publicBasePath: "/", |
||||
|
privateBasePath: "/", |
||||
|
privateBaseUrl: params.PRIVATE_BASE_URL ], |
||||
|
toolbox: [ openshiftProject: params.NAMESPACE, |
||||
|
destination: params.TARGET_INSTANCE, |
||||
|
image: "quay.io/redhat/3scale-toolbox:v0.16.2", |
||||
|
activeDeadlineSeconds: 180, |
||||
|
insecure: params.DISABLE_TLS_VALIDATION == "yes", |
||||
|
secretName: params.SECRET_NAME], |
||||
|
service: [:], |
||||
|
applications: [ |
||||
|
[ name: "petstore-app", description: "This is used for tests", plan: "test", account: "john" ] |
||||
|
], |
||||
|
applicationPlans: [ |
||||
|
[ systemName: "test", name: "Test", defaultPlan: true, published: true ] |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
// A pre-release version needs to use the mock backend |
||||
|
//if (service.openapi.majorVersion == "0") { |
||||
|
// service.environment.privateBaseUrl = params.MOCK_SERVER |
||||
|
// service.environment.privateBasePath = params.MOCK_URL |
||||
|
//} |
||||
|
|
||||
|
// Import OpenAPI |
||||
|
service.importOpenAPI() |
||||
|
echo "Service with system_name ${service.environment.targetSystemName} created !" |
||||
|
|
||||
|
// Create an Application Plan |
||||
|
service.applyApplicationPlans() |
||||
|
|
||||
|
// Create an Application |
||||
|
service.applyApplication() |
||||
|
|
||||
|
// Promote to production |
||||
|
service.promoteToProduction() |
||||
|
} |
||||
|
|
||||
|
// Terminate the pipeline earlier if the API is not yet production ready |
||||
|
if (service.openapi.majorVersion == "0") { |
||||
|
currentBuild.result = 'SUCCESS' |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
stage("Deploy API in Test") { |
||||
|
// Prepare |
||||
|
service = toolbox.prepareThreescaleService( |
||||
|
openapi: [filename: "openapi.json" ], |
||||
|
environment: [ baseSystemName: "library", |
||||
|
environmentName: "test", |
||||
|
oidcIssuerEndpoint: params.OIDC_ISSUER_ENDPOINT, |
||||
|
publicBasePath: "/", |
||||
|
privateBasePath: "/", |
||||
|
privateBaseUrl: params.PRIVATE_BASE_URL ], |
||||
|
toolbox: [ openshiftProject: params.NAMESPACE, |
||||
|
destination: params.TARGET_INSTANCE, |
||||
|
image: "quay.io/redhat/3scale-toolbox:v0.16.2", |
||||
|
activeDeadlineSeconds: 180, |
||||
|
insecure: params.DISABLE_TLS_VALIDATION == "yes", |
||||
|
secretName: params.SECRET_NAME], |
||||
|
service: [:], |
||||
|
applications: [ |
||||
|
[ name: "petstore-app", description: "This is used for tests", plan: "test", account: "john" ] |
||||
|
], |
||||
|
applicationPlans: [ |
||||
|
[ systemName: "test", name: "Test", defaultPlan: true, published: true ] |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
// Import OpenAPI |
||||
|
service.importOpenAPI() |
||||
|
echo "Service with system_name ${service.environment.targetSystemName} created !" |
||||
|
|
||||
|
// Create an Application Plan |
||||
|
service.applyApplicationPlans() |
||||
|
|
||||
|
// Create an Application |
||||
|
service.applyApplication() |
||||
|
|
||||
|
// Run integration tests |
||||
|
//runIntegrationTests(service) |
||||
|
|
||||
|
// Promote to production |
||||
|
service.promoteToProduction() |
||||
|
} |
||||
|
|
||||
|
stage("Deploy API in Prod") { |
||||
|
// Prepare |
||||
|
service = toolbox.prepareThreescaleService( |
||||
|
openapi: [filename: "openapi.json" ], |
||||
|
environment: [ baseSystemName: "library", |
||||
|
environmentName: "prod", |
||||
|
oidcIssuerEndpoint: params.OIDC_ISSUER_ENDPOINT, |
||||
|
publicBasePath: "/", |
||||
|
privateBasePath: "/", |
||||
|
privateBaseUrl: params.PRIVATE_BASE_URL ], |
||||
|
toolbox: [ openshiftProject: params.NAMESPACE, |
||||
|
destination: params.TARGET_INSTANCE, |
||||
|
image: "quay.io/redhat/3scale-toolbox:v0.16.2", |
||||
|
activeDeadlineSeconds: 180, |
||||
|
insecure: params.DISABLE_TLS_VALIDATION == "yes", |
||||
|
secretName: params.SECRET_NAME], |
||||
|
service: [:], |
||||
|
applications: [ |
||||
|
[ name: "petstore-app", description: "This is used for tests", plan: "silver", account: "john" ] |
||||
|
], |
||||
|
applicationPlans: [ |
||||
|
[ systemName: "gold", name: "Gold", defaultPlan: false, published: true ], |
||||
|
[ systemName: "silver", name: "Silver", defaultPlan: true, published: true ] |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
// Import OpenAPI |
||||
|
service.importOpenAPI() |
||||
|
echo "Service with system_name ${service.environment.targetSystemName} created !" |
||||
|
|
||||
|
// Create an Application Plan |
||||
|
service.applyApplicationPlans() |
||||
|
|
||||
|
// Create an Application |
||||
|
service.applyApplication() |
||||
|
|
||||
|
// Promote to production |
||||
|
service.promoteToProduction() |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
def runIntegrationTests(def service) { |
||||
|
// To run the integration tests when using APIcast SaaS instances, we need |
||||
|
// to fetch the proxy definition to extract the staging public url |
||||
|
def proxy = service.readProxy("sandbox") |
||||
|
|
||||
|
// The integration tests will be a bit different depending on the security scheme |
||||
|
// declared in the OpenAPI Specification file |
||||
|
def getCredentialsCodeSnippet = null |
||||
|
if (service.openapi.securityScheme.name() == "OPEN") { |
||||
|
getCredentialsCodeSnippet = """ |
||||
|
credential_header="x-dummy: dummy" |
||||
|
echo "no credential will be used" |
||||
|
""" |
||||
|
} else if (service.openapi.securityScheme.name() == "APIKEY") { |
||||
|
def userkey = service.applications[0].userkey |
||||
|
getCredentialsCodeSnippet = """ |
||||
|
credential_header="api-key: ${userkey}" |
||||
|
echo "userkey is ${userkey}" |
||||
|
""" |
||||
|
} else if (service.openapi.securityScheme.name() == "OIDC") { |
||||
|
def tokenEndpoint = getTokenEndpoint(params.OIDC_ISSUER_ENDPOINT) |
||||
|
def clientId = service.applications[0].clientId |
||||
|
def clientSecret = service.applications[0].clientSecret |
||||
|
getCredentialsCodeSnippet = """ |
||||
|
echo "token endpoint is ${tokenEndpoint}" |
||||
|
echo "client_id=${clientId}" |
||||
|
echo "client_secret=${clientSecret}" |
||||
|
curl -sfk "${tokenEndpoint}" -d client_id="${clientId}" -d client_secret="${clientSecret}" -d scope=openid -d grant_type=client_credentials -o response.json |
||||
|
TOKEN="\$(/tmp/jq -r .access_token response.json)" |
||||
|
echo "Received access_token '\$TOKEN'" |
||||
|
credential_header="Authorization: Bearer \$TOKEN" |
||||
|
""" |
||||
|
} |
||||
|
|
||||
|
// Run the actual tests |
||||
|
sh """set -e |
||||
|
echo "Public Staging Base URL is ${proxy.sandbox_endpoint}" |
||||
|
${getCredentialsCodeSnippet} |
||||
|
curl -sfk -w "findPets: %{http_code}\n" -o /dev/null "${proxy.sandbox_endpoint}/pets" -H "\$credential_header" |
||||
|
curl -sfk -w "findPetById: %{http_code}\n" -o /dev/null "${proxy.sandbox_endpoint}/pets/1" -H "\$credential_header" |
||||
|
# This one is only present in v1.1 and onwards |
||||
|
curl -sk -w "updatePet: %{http_code}\n" -o /dev/null "${proxy.sandbox_endpoint}/pets/1" -H "Content-Type: application/json" -XPUT -d '{"id":1,"name":"Raspoutine","tag":"dog"}' -H "\$credential_header" |
||||
|
""" |
||||
|
} |
||||
|
|
||||
|
def getTokenEndpoint(String oidcIssuerEndpoint) { |
||||
|
def m = (oidcIssuerEndpoint =~ /(https?:\/\/)[^:]+:[^@]+@(.*)/) |
||||
|
return "${m[0][1]}${m[0][2]}/protocol/openid-connect/token" |
||||
|
} |
||||
@ -1,11 +1,58 @@ |
|||||
# Library API |
# Library API |
||||
|
|
||||
``` |
## Setup |
||||
|
|
||||
|
Create a project and deploy the Library API Backend. |
||||
|
|
||||
|
```sh |
||||
oc new-project library-api |
oc new-project library-api |
||||
oc create secret generic 3scale-toolbox -n library-api --from-file="$HOME/.3scalerc.yaml" |
oc import-image -n openshift openjdk-8-rhel8 --from=registry.redhat.io/openjdk/openjdk-8-rhel8 --confirm --reference-policy=local |
||||
oc new-app -n library-api --template=jenkins-ephemeral --name=jenkins -p MEMORY_LIMIT=2Gi |
|
||||
oc set env -n library-api dc/jenkins JENKINS_OPTS=--sessionTimeout=86400 |
|
||||
oc import-image openjdk-8-rhel8 --from=registry.redhat.io/openjdk/openjdk-8-rhel8 --confirm -n openshift --reference-policy=local |
|
||||
oc new-app -n library-api -i openjdk-8-rhel8 https://github.com/nmasse-itix/library-api.git --name=library-api |
oc new-app -n library-api -i openjdk-8-rhel8 https://github.com/nmasse-itix/library-api.git --name=library-api |
||||
oc expose -n library-api svc/library-api --hostname="library-api.apps.ocp4.itix.fr" |
oc expose -n library-api svc/library-api --hostname="library-api.apps.ocp4.itix.fr" |
||||
``` |
``` |
||||
|
|
||||
|
Deploy a Jenkins master. |
||||
|
|
||||
|
```sh |
||||
|
oc new-app -n library-api --template=jenkins-ephemeral --name=jenkins -p MEMORY_LIMIT=2Gi |
||||
|
oc set env -n library-api dc/jenkins JENKINS_OPTS=--sessionTimeout=86400 |
||||
|
``` |
||||
|
|
||||
|
Create a secret containing your 3scale toolbox remotes. |
||||
|
|
||||
|
```sh |
||||
|
oc create -n library-api secret generic 3scale-toolbox --from-file="$HOME/.3scalerc.yaml" |
||||
|
``` |
||||
|
|
||||
|
Add a new Build Config to run the Jenkins pipeline. |
||||
|
|
||||
|
```sh |
||||
|
oc new-build -n library-api --strategy=pipeline --name=library-pipeline https://github.com/nmasse-itix/library-api.git -e PRIVATE_BASE_URL=http://library-api.apps.ocp4.itix.fr -e NAMESPACE=library-api -e TARGET_INSTANCE=3scale-saas -e SECRET_NAME=3scale-toolbox -e OIDC_ISSUER_ENDPOINT=https://zync:[REDACTED]@sso.apps.ocp4.itix.fr/auth/realms/3scale-saas -e DISABLE_TLS_VALIDATION=yes -e MOCK_SERVER=https://microcks.apps.ocp4.itix.fr -e MOCK_URL=/rest/Library/0.9.0 |
||||
|
``` |
||||
|
|
||||
|
## Reset |
||||
|
|
||||
|
Remove the Jenkins pipeline: |
||||
|
|
||||
|
```sh |
||||
|
oc delete -n library-api bc/library-pipeline |
||||
|
``` |
||||
|
|
||||
|
Remove the 3scale services: |
||||
|
|
||||
|
```sh |
||||
|
ansible-playbook cleanup/cleanup.yml -e admin_portal_hostname=[TENANT]-admin.3scale.net -e threescale_token=[REDACTED] |
||||
|
``` |
||||
|
|
||||
|
Go to the [Apicurio Studio](https://apicurio-studio.app.itix.fr/apis) and remove the **Library** service. |
||||
|
|
||||
|
Go to the Microcks console and remove the **Library** service. |
||||
|
|
||||
|
Set the OpenAPI Specification file back to version 0.9: |
||||
|
|
||||
|
```sh |
||||
|
mv api-contracts/openapi-0.9.json openapi.json |
||||
|
git add openapi.json |
||||
|
git commit -m 'reset the demo' |
||||
|
git push |
||||
|
``` |
||||
|
|||||
@ -0,0 +1,87 @@ |
|||||
|
--- |
||||
|
|
||||
|
- name: Delete petstore services of a 3scale tenant |
||||
|
hosts: localhost |
||||
|
gather_facts: no |
||||
|
vars: |
||||
|
ansible_connection: local |
||||
|
threescale_api: https://{{ admin_portal_hostname }}/admin/api |
||||
|
find_in_systemname: library |
||||
|
validate_certs: no |
||||
|
tasks: |
||||
|
- assert: |
||||
|
that: |
||||
|
- threescale_token is defined |
||||
|
- admin_portal_hostname is defined |
||||
|
msg: > |
||||
|
Please pass your 3scale Access Token in the 'threescale_token' extra var |
||||
|
and your 3scale Admin Portal hostname in the 'admin_portal_hostname' extra var. |
||||
|
|
||||
|
- name: Find Services |
||||
|
uri: |
||||
|
url: '{{ threescale_api }}/services.json?access_token={{ threescale_token }}' |
||||
|
validate_certs: '{{ validate_certs }}' |
||||
|
register: find_services_response |
||||
|
changed_when: false |
||||
|
|
||||
|
- name: Delete all matching services |
||||
|
uri: |
||||
|
url: '{{ threescale_api }}/services/{{ item.id }}.json?access_token={{ threescale_token }}' |
||||
|
method: DELETE |
||||
|
status_code: "200,404" |
||||
|
validate_certs: '{{ validate_certs }}' |
||||
|
register: delete_service_response |
||||
|
changed_when: delete_service_response.status == 200 |
||||
|
with_items: '{{ services }}' |
||||
|
when: > |
||||
|
find_in_systemname in item.system_name |
||||
|
vars: |
||||
|
services: '{{ find_services_response.json|json_query(query) }}' |
||||
|
query: > |
||||
|
services[?service.system_name != `api`].{"id": service.id, "system_name": service.system_name} |
||||
|
|
||||
|
- name: Find API Backends |
||||
|
uri: |
||||
|
url: '{{ threescale_api }}/backend_apis.json?access_token={{ threescale_token }}' |
||||
|
validate_certs: '{{ validate_certs }}' |
||||
|
register: find_backends_response |
||||
|
changed_when: false |
||||
|
|
||||
|
- name: Delete all matching API Backends |
||||
|
uri: |
||||
|
url: '{{ threescale_api }}/backend_apis/{{ item.id }}.json?access_token={{ threescale_token }}' |
||||
|
method: DELETE |
||||
|
status_code: "200,404" |
||||
|
validate_certs: '{{ validate_certs }}' |
||||
|
register: delete_service_response |
||||
|
changed_when: delete_service_response.status == 200 |
||||
|
with_items: '{{ services }}' |
||||
|
when: > |
||||
|
find_in_systemname in item.system_name |
||||
|
vars: |
||||
|
services: '{{ find_backends_response.json|json_query(query) }}' |
||||
|
query: > |
||||
|
backend_apis[?backend_api.system_name != `api`].{"id": backend_api.id, "system_name": backend_api.system_name} |
||||
|
|
||||
|
- name: Find ActiveDocs |
||||
|
uri: |
||||
|
url: '{{ threescale_api }}/active_docs.json?access_token={{ threescale_token }}' |
||||
|
validate_certs: '{{ validate_certs }}' |
||||
|
register: find_active_docs_response |
||||
|
changed_when: false |
||||
|
|
||||
|
- name: Delete all matching ActiveDocs |
||||
|
uri: |
||||
|
url: '{{ threescale_api }}/active_docs/{{ item.id }}.json?access_token={{ threescale_token }}' |
||||
|
method: DELETE |
||||
|
status_code: "200,404" |
||||
|
validate_certs: '{{ validate_certs }}' |
||||
|
register: delete_active_docs_response |
||||
|
changed_when: delete_active_docs_response.status == 200 |
||||
|
with_items: '{{ active_docs }}' |
||||
|
when: > |
||||
|
find_in_systemname in item.system_name |
||||
|
vars: |
||||
|
active_docs: '{{ find_active_docs_response.json|json_query(query) }}' |
||||
|
query: > |
||||
|
api_docs[?api_doc.system_name != `echo`].{"id": api_doc.id, "system_name": api_doc.system_name} |
||||
Loading…
Reference in new issue