From 80124e89250a6ca1b482b86005ef678ad51d0da0 Mon Sep 17 00:00:00 2001 From: dandds Date: Thu, 29 Nov 2018 09:29:46 -0500 Subject: [PATCH 01/19] basic test config --- deploy/kubernetes/test/atst-configmap.yml | 15 ++ .../test/atst-envvars-configmap.yml | 11 + .../kubernetes/test/atst-nginx-configmap.yml | 79 ++++++ .../test/atst-worker-envvars-configmap.yml | 8 + deploy/kubernetes/test/test.yml | 226 ++++++++++++++++++ 5 files changed, 339 insertions(+) create mode 100644 deploy/kubernetes/test/atst-configmap.yml create mode 100644 deploy/kubernetes/test/atst-envvars-configmap.yml create mode 100644 deploy/kubernetes/test/atst-nginx-configmap.yml create mode 100644 deploy/kubernetes/test/atst-worker-envvars-configmap.yml create mode 100644 deploy/kubernetes/test/test.yml diff --git a/deploy/kubernetes/test/atst-configmap.yml b/deploy/kubernetes/test/atst-configmap.yml new file mode 100644 index 00000000..54409d7d --- /dev/null +++ b/deploy/kubernetes/test/atst-configmap.yml @@ -0,0 +1,15 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: atst-config + namespace: atat-test +data: + uwsgi-config: |- + [uwsgi] + callable = app + module = app + socket = /var/run/uwsgi/uwsgi.socket + plugins = python3 + virtualenv = /opt/atat/atst/.venv + chmod-socket = 666 diff --git a/deploy/kubernetes/test/atst-envvars-configmap.yml b/deploy/kubernetes/test/atst-envvars-configmap.yml new file mode 100644 index 00000000..94c24d9a --- /dev/null +++ b/deploy/kubernetes/test/atst-envvars-configmap.yml @@ -0,0 +1,11 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: atst-envvars + namespace: atat-test +data: + FLASK_ENV: dev + OVERRIDE_CONFIG_FULLPATH: /opt/atat/atst/atst-overrides.ini + UWSGI_CONFIG_FULLPATH: /opt/atat/atst/uwsgi-config.ini + RQ_QUEUES: atat-test diff --git a/deploy/kubernetes/test/atst-nginx-configmap.yml b/deploy/kubernetes/test/atst-nginx-configmap.yml new file mode 100644 index 00000000..a425c818 --- /dev/null +++ b/deploy/kubernetes/test/atst-nginx-configmap.yml @@ -0,0 +1,79 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: atst-nginx + namespace: atat-test +data: + nginx-config: |- + server { + server_name test.atat.code.mil; + listen 8442; + listen [::]:8442 ipv6only=on; + if ($http_x_forwarded_proto != 'https') { + return 301 https://$host$request_uri; + } + location /login-redirect { + return 301 https://auth-test.atat.code.mil$request_uri; + } + location /login-dev { + try_files $uri @appbasicauth; + } + location / { + try_files $uri @app; + } + location @app { + include uwsgi_params; + uwsgi_pass unix:///var/run/uwsgi/uwsgi.socket; + } + location @appbasicauth { + include uwsgi_params; + uwsgi_pass unix:///var/run/uwsgi/uwsgi.socket; + auth_basic "Developer Access"; + auth_basic_user_file /etc/nginx/.htpasswd; + } + } + server { + server_name auth-test.atat.code.mil; + listen 8443 ssl; + listen [::]:8443 ssl ipv6only=on; + # SSL server certificate and private key + ssl_certificate /etc/ssl/private/auth.atat.crt; + ssl_certificate_key /etc/ssl/private/auth.atat.key; + # Set SSL protocols, ciphers, and related options + ssl_protocols TLSv1.3 TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + ssl_prefer_server_ciphers on; + ssl_ecdh_curve secp384r1; + ssl_dhparam /etc/ssl/dhparam.pem; + # SSL session options + ssl_session_timeout 4h; + ssl_session_cache shared:SSL:10m; # 1mb = ~4000 sessions + ssl_session_tickets off; + # OCSP Stapling + ssl_stapling on; + ssl_stapling_verify on; + resolver 8.8.8.8 8.8.4.4; + # Request and validate client certificate + ssl_verify_client on; + ssl_verify_depth 10; + ssl_client_certificate /etc/ssl/client-ca-bundle.pem; + # Guard against HTTPS -> HTTP downgrade + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; always"; + location / { + return 301 https://test.atat.code.mil$request_uri; + } + location /login-redirect { + try_files $uri @app; + } + location @app { + include uwsgi_params; + uwsgi_pass unix:///var/run/uwsgi/uwsgi.socket; + uwsgi_param HTTP_X_SSL_CLIENT_VERIFY $ssl_client_verify; + uwsgi_param HTTP_X_SSL_CLIENT_CERT $ssl_client_raw_cert; + uwsgi_param HTTP_X_SSL_CLIENT_S_DN $ssl_client_s_dn; + uwsgi_param HTTP_X_SSL_CLIENT_S_DN_LEGACY $ssl_client_s_dn_legacy; + uwsgi_param HTTP_X_SSL_CLIENT_I_DN $ssl_client_i_dn; + uwsgi_param HTTP_X_SSL_CLIENT_I_DN_LEGACY $ssl_client_i_dn_legacy; + } + } diff --git a/deploy/kubernetes/test/atst-worker-envvars-configmap.yml b/deploy/kubernetes/test/atst-worker-envvars-configmap.yml new file mode 100644 index 00000000..73102195 --- /dev/null +++ b/deploy/kubernetes/test/atst-worker-envvars-configmap.yml @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: atst-worker-envvars + namespace: atat-test +data: + REQUIRE_CRLS: "False" diff --git a/deploy/kubernetes/test/test.yml b/deploy/kubernetes/test/test.yml new file mode 100644 index 00000000..0d46db4f --- /dev/null +++ b/deploy/kubernetes/test/test.yml @@ -0,0 +1,226 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: atat-test +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: atst + name: atst + namespace: atat-test +spec: + replicas: 1 + strategy: + type: RollingUpdate + template: + metadata: + labels: + app: atst + spec: + securityContext: + fsGroup: 101 + containers: + - name: atst + image: registry.atat.codes:443/atst-prod:a9fc2bd2 + resources: + requests: + memory: "2500Mi" + envFrom: + - configMapRef: + name: atst-envvars + volumeMounts: + - name: atst-config + mountPath: "/opt/atat/atst/atst-overrides.ini" + subPath: atst-overrides.ini + - name: nginx-client-ca-bundle + mountPath: "/opt/atat/atst/ssl/server-certs/ca-chain.pem" + subPath: client-ca-bundle.pem + - name: uwsgi-config + mountPath: "/opt/atat/atst/uwsgi-config.ini" + subPath: uwsgi-config.ini + - name: uwsgi-socket-dir + mountPath: "/var/run/uwsgi" + - name: atst-nginx + image: nginx:alpine + ports: + - containerPort: 8442 + name: http + - containerPort: 8443 + name: https + volumeMounts: + - name: nginx-auth-tls + mountPath: "/etc/ssl/private" + - name: nginx-client-ca-bundle + mountPath: "/etc/ssl/client-ca-bundle.pem" + subPath: client-ca-bundle.pem + - name: nginx-config + mountPath: "/etc/nginx/conf.d/atst.conf" + subPath: atst.conf + - name: nginx-dhparam + mountPath: "/etc/ssl/dhparam.pem" + subPath: dhparam.pem + - name: nginx-htpasswd + mountPath: "/etc/nginx/.htpasswd" + subPath: .htpasswd + - name: uwsgi-socket-dir + mountPath: "/var/run/uwsgi" + imagePullSecrets: + - name: regcred + volumes: + - name: atst-config + secret: + secretName: atst-config-ini + items: + - key: override.ini + path: atst-overrides.ini + mode: 0644 + - name: nginx-auth-tls + secret: + secretName: atst-auth-test-ingress-tls + items: + - key: tls.crt + path: auth.atat.crt + mode: 0644 + - key: tls.key + path: auth.atat.key + mode: 0640 + - name: nginx-client-ca-bundle + secret: + secretName: nginx-client-ca-bundle + items: + - key: client-ca-bundle.pem + path: client-ca-bundle.pem + mode: 0666 + - name: nginx-config + configMap: + name: atst-nginx + items: + - key: nginx-config + path: atst.conf + - name: nginx-dhparam + secret: + secretName: dhparam-4096 + items: + - key: dhparam.pem + path: dhparam.pem + mode: 0640 + - name: nginx-htpasswd + secret: + secretName: atst-nginx-htpasswd + items: + - key: htpasswd + path: .htpasswd + mode: 0640 + - name: uwsgi-config + configMap: + name: atst-config + items: + - key: uwsgi-config + path: uwsgi-config.ini + mode: 0644 + - name: uwsgi-socket-dir + emptyDir: + medium: Memory +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: atst + name: atst-worker + namespace: atat-test +spec: + replicas: 1 + strategy: + type: RollingUpdate + template: + metadata: + labels: + app: atst + spec: + securityContext: + fsGroup: 101 + containers: + - name: atst-worker + image: registry.atat.codes:443/atst-prod:a9fc2bd2 + args: ["/bin/bash", "-c", "/opt/atat/atst/script/rq_worker"] + resources: + requests: + memory: "500Mi" + envFrom: + - configMapRef: + name: atst-envvars + - configMapRef: + name: atst-worker-envvars + volumeMounts: + - name: atst-config + mountPath: "/opt/atat/atst/atst-overrides.ini" + subPath: atst-overrides.ini + imagePullSecrets: + - name: regcred + volumes: + - name: atst-config + secret: + secretName: atst-config-ini + items: + - key: override.ini + path: atst-overrides.ini + mode: 0644 +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: atst + name: atst + namespace: atat-test +spec: + ports: + - name: http + port: 80 + targetPort: 8442 + selector: + app: atst +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: atst + name: atst-auth + namespace: atat-test +spec: + type: NodePort + ports: + - name: https + protocol: TCP + nodePort: 32701 + port: 8443 + selector: + app: atst +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: atst + namespace: atat-test + annotations: + kubernetes.io/tls-acme: "true" + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/proxy-body-size: 10m +spec: + tls: + - secretName: atst-test-ingress-tls + hosts: + - test.atat.code.mil + rules: + - host: test.atat.code.mil + http: + paths: + - path: / + backend: + serviceName: atst + servicePort: 80 From 1cea2b63ac7e6b8d51da04eca79375c349812d95 Mon Sep 17 00:00:00 2001 From: dandds Date: Thu, 29 Nov 2018 13:50:14 -0500 Subject: [PATCH 02/19] update auth port for test environment --- deploy/kubernetes/test/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kubernetes/test/test.yml b/deploy/kubernetes/test/test.yml index 0d46db4f..b317d921 100644 --- a/deploy/kubernetes/test/test.yml +++ b/deploy/kubernetes/test/test.yml @@ -197,7 +197,7 @@ spec: ports: - name: https protocol: TCP - nodePort: 32701 + nodePort: 32711 port: 8443 selector: app: atst From 52722267251422729e901cdcd090e889af1b0598 Mon Sep 17 00:00:00 2001 From: dandds Date: Thu, 29 Nov 2018 16:07:42 -0500 Subject: [PATCH 03/19] update image for test env, remove unused secret --- deploy/kubernetes/test/test.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/deploy/kubernetes/test/test.yml b/deploy/kubernetes/test/test.yml index b317d921..362e4f0e 100644 --- a/deploy/kubernetes/test/test.yml +++ b/deploy/kubernetes/test/test.yml @@ -24,7 +24,7 @@ spec: fsGroup: 101 containers: - name: atst - image: registry.atat.codes:443/atst-prod:a9fc2bd2 + image: registry.atat.codes:443/atst-prod:24b2543c resources: requests: memory: "2500Mi" @@ -35,9 +35,6 @@ spec: - name: atst-config mountPath: "/opt/atat/atst/atst-overrides.ini" subPath: atst-overrides.ini - - name: nginx-client-ca-bundle - mountPath: "/opt/atat/atst/ssl/server-certs/ca-chain.pem" - subPath: client-ca-bundle.pem - name: uwsgi-config mountPath: "/opt/atat/atst/uwsgi-config.ini" subPath: uwsgi-config.ini @@ -145,7 +142,7 @@ spec: fsGroup: 101 containers: - name: atst-worker - image: registry.atat.codes:443/atst-prod:a9fc2bd2 + image: registry.atat.codes:443/atst-prod:24b2543c args: ["/bin/bash", "-c", "/opt/atat/atst/script/rq_worker"] resources: requests: From 689f7723dc5872287f54add6bfc261dbb5fc289f Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 30 Nov 2018 10:15:04 -0500 Subject: [PATCH 04/19] add readme for creating new site --- deploy/kubernetes/README.md | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 deploy/kubernetes/README.md diff --git a/deploy/kubernetes/README.md b/deploy/kubernetes/README.md new file mode 100644 index 00000000..523db9b8 --- /dev/null +++ b/deploy/kubernetes/README.md @@ -0,0 +1,81 @@ +# Adding a New Environment + +## New Config + +Add a new subfolder to this directory. You can copy `uat` or `tests`. You'll need to change any references to the previous environment name (i.e., `uat`) to your new environment name. This includes things like the k8s namespace and the subdomain for the new site. + +## New Load Balancers + +You need two new load balancers. Currently, these are managed in Rackspace. You will need one for the regular site and one for the auth domain. They should have all of the Kubernetes worker nodes attached. When attached to the LB for the main site domain, the nodes should point to port 32761, which is the port where all our NGINX ingress is managed. The auth LB nodes should point to a new port in the 32700 - 32799 range. + +## Initially Apply the New Config + +Apply your new environment config to create the namespace. Pod creation will fail at this point. + +``` +kubectl -n my-new-env apply -f deploy/kubernetes/my-new-env/ +``` + +## Create New Secrets + +You should then copy and duplicate the secrets from another environment. + +### Adjust the INI Config for the New Site + +You can duplicate the override.ini file from one of the existing sites. For instance, to get the `atst-config-ini` secret for the UAT env: + +``` +kubectl -n atat-uat get secret atst-config-ini -o yaml > uat-secrets.yml +``` + +You can copy the base64 secret content from the `uat-secrets.yml` file. Decode it into a new `override.ini` file: + +``` +echo '[Paste in the long base64 string here]' | base64 --decode > override.ini +``` + +Edit and adjust the application config as needed for your new site. Then add it as a secret: + +``` +kubectl -n my-new-env create secret generic atst-config-ini --from-file=override.ini +``` + +### Add a New htpasswd + +Create a new htpasswd to protect the dev login of the new site: + +``` +htpasswd -c htpasswd atat +``` + +You'll be prompted for the new password. Then add it as a secret: + +``` +kubectl -n my-new-env create secret generic atst-nginx-htpasswd --from-file=htpasswd +``` + +### Duplicate the Rest + +You should also the `dhparam-4096` and `nginx-client-ca-bundle` secrets. These can be copied from an existing environment to yours without any changes. The TLS secrets and token will be handled by another service. + +## Disable SSL + +In order for [kube-lego](https://github.com/jetstack/kube-lego) to generate new certs for your site, you have to temporarily disable SSL for your new load balancers. + +For both your LBs, set them to use HTTP/80. Delete the attached nodes for both and re-add them, setting them to use port 32760. This will allow kube-lego to do its job. + +To monitor the process, find the pod ID for the kube-lego worker. To find it, look in the output for: + +``` +kubectl -n kube-system get all +``` + +Then once you know the pod name: + +``` +kubectl -n kube-system --kubeconfig ~/.kube/atat log kube-lego-b96b7bc5c-9fmcv -f --tail=10 +``` + +You will see output about kube-lego attempts to create certs for your new site. + +Once kube-lego is successful, you should restore your load balancers to the config they had initially. Additionally, you should enable HTTPS redirects. From 23294b2e2b24f1a3fd8a8c49a2cc0357093ec5c4 Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 30 Nov 2018 11:10:56 -0500 Subject: [PATCH 05/19] note nodePort must match auth load balancer --- deploy/kubernetes/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kubernetes/README.md b/deploy/kubernetes/README.md index 523db9b8..3f3b5eb2 100644 --- a/deploy/kubernetes/README.md +++ b/deploy/kubernetes/README.md @@ -6,7 +6,7 @@ Add a new subfolder to this directory. You can copy `uat` or `tests`. You'll nee ## New Load Balancers -You need two new load balancers. Currently, these are managed in Rackspace. You will need one for the regular site and one for the auth domain. They should have all of the Kubernetes worker nodes attached. When attached to the LB for the main site domain, the nodes should point to port 32761, which is the port where all our NGINX ingress is managed. The auth LB nodes should point to a new port in the 32700 - 32799 range. +You need two new load balancers. Currently, these are managed in Rackspace. You will need one for the regular site and one for the auth domain. They should have all of the Kubernetes worker nodes attached. When attached to the LB for the main site domain, the nodes should point to port 32761, which is the port where all our NGINX ingress is managed. The auth LB nodes should point to a new port in the 32700 - 32799 range. The `nodePort` specified in your new environment's config should match this port. ## Initially Apply the New Config From b54e3147c3f847666288e048b4843c38f5aaab2a Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 30 Nov 2018 11:32:14 -0500 Subject: [PATCH 06/19] try scheduling nightly deploys for test env with CircleCI config --- .circleci/config.yml | 28 +++++++++++++++++++++++++ deploy/kubernetes/atst-update-deploy.sh | 16 +++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0e17a8f4..43ecbd83 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -195,6 +195,19 @@ jobs: name: "Update Kubernetes Deployment" command: ./deploy/kubernetes/atst-update-deploy.sh + deploy_test: + docker: + - image: *sourceImage + auth: *sourceAuth + environment: *dockerCmdEnvironment + working_directory: *workingDirectory + steps: + - attach_workspace: + at: . + - run: + name: "Update Kubernetes Deployment" + command: ./deploy/kubernetes/atst-update-deploy.sh atat-test + workflows: version: 2 run-tests: @@ -215,3 +228,18 @@ workflows: filters: branches: only: master + nightly: + triggers: + - schedule: + cron: "0 0 * * *" + filters: + branches: + only: + - master + jobs: + - deploy_test: + requires: + - build_and_push_image + filters: + branches: + only: master diff --git a/deploy/kubernetes/atst-update-deploy.sh b/deploy/kubernetes/atst-update-deploy.sh index ff6d93e7..ed4ce0ce 100755 --- a/deploy/kubernetes/atst-update-deploy.sh +++ b/deploy/kubernetes/atst-update-deploy.sh @@ -11,6 +11,12 @@ set -o nounset # Config MAX_DEPLOY_WAIT='300' +if [[ $# -eq 0 ]]; then + NAMESPACE=atat +else + NAMESPACE=$1 +fi + if [ "${IMAGE_NAME}x" = "x" ] then IMAGE_NAME="${ATAT_DOCKER_REGISTRY_URL}/${PROD_IMAGE_NAME}:${GIT_SHA}" @@ -44,15 +50,15 @@ kubectl config use-context atst-deployer kubectl config current-context # Update the ATST deployment -kubectl -n atat set image deployment.apps/atst atst="${IMAGE_NAME}" -kubectl -n atat set image deployment.apps/atst-worker atst-worker="${IMAGE_NAME}" +kubectl -n ${NAMESPACE} set image deployment.apps/atst atst="${IMAGE_NAME}" +kubectl -n ${NAMESPACE} set image deployment.apps/atst-worker atst-worker="${IMAGE_NAME}" # Wait for deployment to finish -if ! timeout -t "${MAX_DEPLOY_WAIT}" -s INT kubectl -n atat rollout status deployment/atst +if ! timeout -t "${MAX_DEPLOY_WAIT}" -s INT kubectl -n ${NAMESPACE} rollout status deployment/atst then # Deploy did not finish before max wait time; abort and rollback the deploy - kubectl -n atat rollout undo deployment/atst - kubectl -n atat rollout undo deployment/atst-worker + kubectl -n ${NAMESPACE} rollout undo deployment/atst + kubectl -n ${NAMESPACE} rollout undo deployment/atst-worker # Exit with a non-zero return code exit 2 fi From ef3caa2cf011b742419c442ef11334910b6e52ca Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Mon, 3 Dec 2018 16:10:35 -0500 Subject: [PATCH 07/19] Set focus when no workspace role is selected --- js/components/selector.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/components/selector.js b/js/components/selector.js index 4e599494..ddc074a6 100644 --- a/js/components/selector.js +++ b/js/components/selector.js @@ -84,7 +84,11 @@ export default { onShow: function () { setTimeout(() => { // timeout is a hack to make focus work in Chrome - this.$refs.choices.find(choice => choice.selected).$refs.input[0].focus() + if (this.$refs.choices.find(choice => choice.selected)) { + this.$refs.choices.find(choice => choice.selected).$refs.input[0].focus() + } else { + this.$refs.choices[0].$refs.input[0].focus() + } }, 100) }, From bbeef23c4508746d64b42b7febcfdae3c35356c3 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 3 Dec 2018 09:29:38 -0500 Subject: [PATCH 08/19] test testing build --- .circleci/config.yml | 26 +++++++++++++++++++-- deploy/kubernetes/atst-deployer.yml | 3 +++ deploy/kubernetes/atst-update-deploy.sh | 2 +- deploy/kubernetes/test/atat-deploy-role.yml | 18 ++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 deploy/kubernetes/test/atat-deploy-role.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 43ecbd83..cb4fca41 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -204,6 +204,12 @@ jobs: steps: - attach_workspace: at: . + - run: + name: "Export GIT_SHA" + command: echo "export GIT_SHA=$(git rev-parse --short HEAD)" >> $BASH_ENV + - run: + name: "Generate the Target Image Name" + command: echo "export IMAGE_NAME=\"${ATAT_DOCKER_REGISTRY_URL}/${PROD_IMAGE_NAME}:${GIT_SHA}\"" >> $BASH_ENV - run: name: "Update Kubernetes Deployment" command: ./deploy/kubernetes/atst-update-deploy.sh atat-test @@ -231,15 +237,31 @@ workflows: nightly: triggers: - schedule: - cron: "0 0 * * *" + cron: "37 * * * *" + # cron: "0 0 * * *" filters: branches: only: - master + - test-env jobs: + - app_setup + - test: + requires: + - app_setup + - build_and_push_image: + requires: + - test + filters: + branches: + only: + - master + - test-env - deploy_test: requires: - build_and_push_image filters: branches: - only: master + only: + - master + - test-env diff --git a/deploy/kubernetes/atst-deployer.yml b/deploy/kubernetes/atst-deployer.yml index ed7950d9..77d94a1b 100644 --- a/deploy/kubernetes/atst-deployer.yml +++ b/deploy/kubernetes/atst-deployer.yml @@ -32,6 +32,9 @@ subjects: - kind: ServiceAccount name: atat-deployer namespace: atat +- kind: ServiceAccount + name: atat-deployer + namespace: atat-test roleRef: kind: Role name: atat-deploy-role diff --git a/deploy/kubernetes/atst-update-deploy.sh b/deploy/kubernetes/atst-update-deploy.sh index ed4ce0ce..d9ade43e 100755 --- a/deploy/kubernetes/atst-update-deploy.sh +++ b/deploy/kubernetes/atst-update-deploy.sh @@ -37,7 +37,7 @@ echo "${K8S_CA_CRT}" | base64 -d - > "${HOME}/k8s_ca.crt" kubectl config set-context atst-deployer \ --cluster=atat-cluster \ --user=atat-deployer \ - --namespace=atat + --namespace=${NAMESPACE} kubectl config set-cluster atat-cluster \ --embed-certs=true \ diff --git a/deploy/kubernetes/test/atat-deploy-role.yml b/deploy/kubernetes/test/atat-deploy-role.yml new file mode 100644 index 00000000..2e2ee7c4 --- /dev/null +++ b/deploy/kubernetes/test/atat-deploy-role.yml @@ -0,0 +1,18 @@ +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + namespace: atat-test + name: atat-deploy-role +rules: +- apiGroups: ["extensions", "apps"] + resources: ["deployments"] + verbs: ["get", "watch", "create", "update", "patch"] +- apiGroups: [""] + resources: ["services"] + verbs: ["get", "create", "update", "patch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create", "update", "patch"] +- apiGroups: ["extensions", "apps"] + resources: ["ingresses"] + verbs: ["get", "create", "update", "patch"] From bd0b7b9dcdbd0a904465ab3c49897d52d2f5ca33 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 4 Dec 2018 09:42:47 -0500 Subject: [PATCH 09/19] script for rotating sample data on test env --- .circleci/config.yml | 5 +- deploy/kubernetes/atst-reset-sample-data.sh | 56 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100755 deploy/kubernetes/atst-reset-sample-data.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index cb4fca41..4ea3a0d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -213,6 +213,9 @@ jobs: - run: name: "Update Kubernetes Deployment" command: ./deploy/kubernetes/atst-update-deploy.sh atat-test + - run: + name: "Reset the Sample Data" + command: ./deploy/kubernetes/atst-reset-sample-data.sh atat-test workflows: version: 2 @@ -237,7 +240,7 @@ workflows: nightly: triggers: - schedule: - cron: "37 * * * *" + cron: "45 * * * *" # cron: "0 0 * * *" filters: branches: diff --git a/deploy/kubernetes/atst-reset-sample-data.sh b/deploy/kubernetes/atst-reset-sample-data.sh new file mode 100755 index 00000000..4210a9bc --- /dev/null +++ b/deploy/kubernetes/atst-reset-sample-data.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# +# deploy/kubernetes/atst-update-deploy.sh: Resets the sample data on the target +# environment. + +set -o pipefail +set -o errexit +set -o nounset +# set -o xtrace + +# Config +MAX_DEPLOY_WAIT='300' + +if [[ $# -eq 0 ]]; then + NAMESPACE=atat +else + NAMESPACE=$1 +fi + +if [ "${IMAGE_NAME}x" = "x" ] +then + IMAGE_NAME="${ATAT_DOCKER_REGISTRY_URL}/${PROD_IMAGE_NAME}:${GIT_SHA}" +fi + +# Remove the K8S CA file when the script exits +function cleanup { + printf "Cleaning up...\n" + rm -vf "${HOME}/k8s_ca.crt" + printf "Cleaning done." +} +trap cleanup EXIT + +# Decode and save the K8S CA cert +echo "${K8S_CA_CRT}" | base64 -d - > "${HOME}/k8s_ca.crt" + +# Setup the local kubectl client +kubectl config set-context atst-deployer \ + --cluster=atat-cluster \ + --user=atat-deployer \ + --namespace=${NAMESPACE} + +kubectl config set-cluster atat-cluster \ + --embed-certs=true \ + --server="${K8S_ENDPOINT}" \ + --certificate-authority="${HOME}/k8s_ca.crt" + +kubectl config set-credentials atat-deployer --token="$(echo ${K8S_USER_TOKEN} | base64 -d -)" + +kubectl config use-context atst-deployer +kubectl config current-context + +# we only need to run these commands against one existing pod +ATST_POD=$(kubectl -n ${NAMESPACE} get pods -l app=atst -o custom-columns=NAME:.metadata.name --no-headers) +kubectl -n ${NAMESPACE} exec ${ATST_POD} -- pipenv run python script/remove_sample_data.py +kubectl -n ${NAMESPACE} exec ${ATST_POD} -- pipenv run python script/seed_sample.py + From f3c294659a453dea322cd1088f58f798fdf2b6b0 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 4 Dec 2018 15:26:16 -0500 Subject: [PATCH 10/19] refine test environment sample data script, add k8s role and role binding for updating sample data --- .circleci/config.yml | 6 +---- deploy/kubernetes/atst-reset-sample-data.sh | 10 +++---- deploy/kubernetes/test/atat-deploy-role.yml | 30 +++++++++++++-------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4ea3a0d4..1976976a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -240,13 +240,11 @@ workflows: nightly: triggers: - schedule: - cron: "45 * * * *" - # cron: "0 0 * * *" + cron: "0 0 * * *" filters: branches: only: - master - - test-env jobs: - app_setup - test: @@ -259,7 +257,6 @@ workflows: branches: only: - master - - test-env - deploy_test: requires: - build_and_push_image @@ -267,4 +264,3 @@ workflows: branches: only: - master - - test-env diff --git a/deploy/kubernetes/atst-reset-sample-data.sh b/deploy/kubernetes/atst-reset-sample-data.sh index 4210a9bc..32e0ea06 100755 --- a/deploy/kubernetes/atst-reset-sample-data.sh +++ b/deploy/kubernetes/atst-reset-sample-data.sh @@ -17,11 +17,6 @@ else NAMESPACE=$1 fi -if [ "${IMAGE_NAME}x" = "x" ] -then - IMAGE_NAME="${ATAT_DOCKER_REGISTRY_URL}/${PROD_IMAGE_NAME}:${GIT_SHA}" -fi - # Remove the K8S CA file when the script exits function cleanup { printf "Cleaning up...\n" @@ -50,7 +45,10 @@ kubectl config use-context atst-deployer kubectl config current-context # we only need to run these commands against one existing pod -ATST_POD=$(kubectl -n ${NAMESPACE} get pods -l app=atst -o custom-columns=NAME:.metadata.name --no-headers) +ATST_POD=$(kubectl -n ${NAMESPACE} get pods -l app=atst -o custom-columns=NAME:.metadata.name --no-headers | sed -n 1p) +# echo "kubectl -n ${NAMESPACE} exec ${ATST_POD} -- pipenv run python script/remove_sample_data.py" +echo "removing sample data on pod ${ATST_POD}" kubectl -n ${NAMESPACE} exec ${ATST_POD} -- pipenv run python script/remove_sample_data.py +echo "seeding sample data on pod ${ATST_POD}" kubectl -n ${NAMESPACE} exec ${ATST_POD} -- pipenv run python script/seed_sample.py diff --git a/deploy/kubernetes/test/atat-deploy-role.yml b/deploy/kubernetes/test/atat-deploy-role.yml index 2e2ee7c4..8a7b6f85 100644 --- a/deploy/kubernetes/test/atat-deploy-role.yml +++ b/deploy/kubernetes/test/atat-deploy-role.yml @@ -2,17 +2,25 @@ kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: namespace: atat-test - name: atat-deploy-role + name: atat-sample-update rules: -- apiGroups: ["extensions", "apps"] - resources: ["deployments"] - verbs: ["get", "watch", "create", "update", "patch"] - apiGroups: [""] - resources: ["services"] - verbs: ["get", "create", "update", "patch"] + resources: ["pods"] + verbs: ["get", "list"] - apiGroups: [""] - resources: ["configmaps"] - verbs: ["get", "create", "update", "patch"] -- apiGroups: ["extensions", "apps"] - resources: ["ingresses"] - verbs: ["get", "create", "update", "patch"] + resources: ["pods/exec"] + verbs: ["create"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: atst-sample-role-binding + namespace: atat-test +subjects: +- kind: ServiceAccount + name: atat-deployer + namespace: atat +roleRef: + kind: Role + name: atat-sample-update + apiGroup: rbac.authorization.k8s.io From 1be7fcdd8ae42369469ee88a23692c4b9d2b842d Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Fri, 30 Nov 2018 11:31:30 -0500 Subject: [PATCH 11/19] Move audit_log template to a directory --- atst/routes/__init__.py | 2 +- templates/{ => audit_log}/audit_log.html | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename templates/{ => audit_log}/audit_log.html (100%) diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index 339cd219..2a1d23bc 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -137,7 +137,7 @@ def get_pagination_opts(request, default_page=1, default_per_page=100): def activity_history(): pagination_opts = get_pagination_opts(request) audit_events = AuditLog.get_all_events(g.current_user, pagination_opts) - return render_template("audit_log.html", audit_events=audit_events) + return render_template("audit_log/audit_log.html", audit_events=audit_events) @bp.route("/about") diff --git a/templates/audit_log.html b/templates/audit_log/audit_log.html similarity index 100% rename from templates/audit_log.html rename to templates/audit_log/audit_log.html From 5d9aeeefed37bbcb66768bbbf3d560c0d7f812bd Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Fri, 30 Nov 2018 11:32:49 -0500 Subject: [PATCH 12/19] Add generated JS coverage to gitignore --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e161f040..c7205185 100644 --- a/.gitignore +++ b/.gitignore @@ -45,8 +45,12 @@ ssl/client-certs/*.srl # uploads /uploads -# coverage output +# python coverage output .coverage +# je coverage output +coverage + + # selenium testing browserstacklocal From d593f7577b53790f4494c994cca7f45edc4d3acc Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 3 Dec 2018 15:54:07 -0500 Subject: [PATCH 13/19] Attempt to look up template for each audit event type --- atst/filters.py | 12 +++++- templates/audit_log/audit_log.html | 56 ++----------------------- templates/audit_log/events/_base.html | 22 ++++++++++ templates/audit_log/events/default.html | 39 +++++++++++++++++ 4 files changed, 75 insertions(+), 54 deletions(-) create mode 100644 templates/audit_log/events/_base.html create mode 100644 templates/audit_log/events/default.html diff --git a/atst/filters.py b/atst/filters.py index c172a3df..f8b8d2d3 100644 --- a/atst/filters.py +++ b/atst/filters.py @@ -1,6 +1,7 @@ import re import datetime -from flask import current_app as app +from flask import current_app as app, render_template +from jinja2.exceptions import TemplateNotFound def iconSvg(name): @@ -86,6 +87,14 @@ def pageWindow(pagination, size=2): return (max(1, (page - size) - over), min(num_pages, (page + size) - under)) +def renderAuditEvent(event): + template_name = 'audit_log/events/{}.html'.format(event.resource_type) + try: + return render_template(template_name, event=event) + except TemplateNotFound: + return render_template('audit_log/events/default.html', event=event) + + def register_filters(app): app.jinja_env.filters["iconSvg"] = iconSvg app.jinja_env.filters["dollars"] = dollars @@ -98,3 +107,4 @@ def register_filters(app): app.jinja_env.filters["formattedDate"] = formattedDate app.jinja_env.filters["dateFromString"] = dateFromString app.jinja_env.filters["pageWindow"] = pageWindow + app.jinja_env.filters["renderAuditEvent"] = renderAuditEvent diff --git a/templates/audit_log/audit_log.html b/templates/audit_log/audit_log.html index cacd164b..3b505135 100644 --- a/templates/audit_log/audit_log.html +++ b/templates/audit_log/audit_log.html @@ -12,59 +12,9 @@
    {% for event in audit_events %}
  • -
    -
    - -
    - -
    -

    - {{ event.user.full_name if event.user else "ATAT System" }} -

    - {{ event.action }} {{ event.resource_type }} {{ event.resource_id }} - {% if event.display_name %} - ({{ event.display_name }}) - {% endif %} - -
    - - {% if event.event_details and event.resource_type == "user" %} - for User {{ event.event_details.updated_user_id }} ({{ event.event_details.updated_user_name }}) - - {% if event.event_details["environment"] %} -
    - in Environment {{ event.event_details["environment_id"] }} ({{ event.event_details["environment"] }}) -
    - in Project {{ event.event_details["project_id"] }} ({{ event.event_details["project"] }}) -
    - in Workspace {{ event.event_details["workspace_id"] }} ({{ event.event_details["workspace"] }}) - {% endif %} -
    - - {% elif event.event_details and event.resource_type == "invitation" %} - {% set accepted = event.changed_state.status and event.changed_state.status.1 == "ACCEPTED" %} - {% if accepted %} - accepted by {{ event.event_details.email }} (DOD {{ event.event_details.dod_id }}) - {% endif %} - {% endif %} - - {% if event.changed_state and event.resource_type == 'environment_role' %} - from {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} -
    - {% endif %} - - {% if event.workspace %} - in Workspace {{ event.workspace_id }} ({{ event.workspace.name }}) - {% elif event.request %} - on Request {{ event.request_id }} ({{ event.request.displayname }}) - {% endif %} - - {% if event.changed_state.role %} - from {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} -
    - {% endif %} -
    -
    + {% autoescape false %} + {{ event | renderAuditEvent }} + {% endautoescape %}
  • {% endfor %}
diff --git a/templates/audit_log/events/_base.html b/templates/audit_log/events/_base.html new file mode 100644 index 00000000..03bd5a94 --- /dev/null +++ b/templates/audit_log/events/_base.html @@ -0,0 +1,22 @@ +
+
+ +
+ +
+ {% block header %} +

+ {{ event.user.full_name if event.user else "ATAT System" }} +

+ {{ event.action }} {{ event.resource_type }} {{ event.resource_id }} + {% if event.display_name %} + ({{ event.display_name }}) + {% endif %} + {% endblock %} + +
+ + {% block content %}{% endblock %} +
+
+ diff --git a/templates/audit_log/events/default.html b/templates/audit_log/events/default.html new file mode 100644 index 00000000..1fae5e5b --- /dev/null +++ b/templates/audit_log/events/default.html @@ -0,0 +1,39 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} + {% if event.event_details and event.resource_type == "user" %} + for User {{ event.event_details.updated_user_id }} ({{ event.event_details.updated_user_name }}) + + {% if event.event_details["environment"] %} +
+ in Environment {{ event.event_details["environment_id"] }} ({{ event.event_details["environment"] }}) +
+ in Project {{ event.event_details["project_id"] }} ({{ event.event_details["project"] }}) +
+ in Workspace {{ event.event_details["workspace_id"] }} ({{ event.event_details["workspace"] }}) + {% endif %} +
+ + {% elif event.event_details and event.resource_type == "invitation" %} + {% set accepted = event.changed_state.status and event.changed_state.status.1 == "ACCEPTED" %} + {% if accepted %} + accepted by {{ event.event_details.email }} (DOD {{ event.event_details.dod_id }}) + {% endif %} + {% endif %} + + {% if event.changed_state and event.resource_type == 'environment_role' %} + from {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} +
+ {% endif %} + + {% if event.workspace %} + in Workspace {{ event.workspace_id }} ({{ event.workspace.name }}) + {% elif event.request %} + on Request {{ event.request_id }} ({{ event.request.displayname }}) + {% endif %} + + {% if event.changed_state.role %} + from {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} +
+ {% endif %} +{% endblock %} From 7c3e0d8fab5c657849e2cef9d099a26671b1347a Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Tue, 4 Dec 2018 11:17:39 -0500 Subject: [PATCH 14/19] Add audit event templates for each type of event --- templates/audit_log/events/environment.html | 5 +++++ templates/audit_log/events/environment_role.html | 13 +++++++++++++ templates/audit_log/events/invitation.html | 8 ++++++++ templates/audit_log/events/project.html | 4 ++++ templates/audit_log/events/request.html | 4 ++++ templates/audit_log/events/request_review.html | 4 ++++ templates/audit_log/events/request_revision.html | 5 +++++ .../audit_log/events/request_status_event.html | 4 ++++ templates/audit_log/events/user.html | 4 ++++ templates/audit_log/events/workspace.html | 1 + templates/audit_log/events/workspace_role.html | 14 ++++++++++++++ 11 files changed, 66 insertions(+) create mode 100644 templates/audit_log/events/environment.html create mode 100644 templates/audit_log/events/environment_role.html create mode 100644 templates/audit_log/events/invitation.html create mode 100644 templates/audit_log/events/project.html create mode 100644 templates/audit_log/events/request.html create mode 100644 templates/audit_log/events/request_review.html create mode 100644 templates/audit_log/events/request_revision.html create mode 100644 templates/audit_log/events/request_status_event.html create mode 100644 templates/audit_log/events/user.html create mode 100644 templates/audit_log/events/workspace.html create mode 100644 templates/audit_log/events/workspace_role.html diff --git a/templates/audit_log/events/environment.html b/templates/audit_log/events/environment.html new file mode 100644 index 00000000..a31a87ef --- /dev/null +++ b/templates/audit_log/events/environment.html @@ -0,0 +1,5 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} + in Workspace {{ event.workspace_id }} ({{ event.workspace.name }}) +{% endblock %} diff --git a/templates/audit_log/events/environment_role.html b/templates/audit_log/events/environment_role.html new file mode 100644 index 00000000..91b7a398 --- /dev/null +++ b/templates/audit_log/events/environment_role.html @@ -0,0 +1,13 @@ +{% extends 'audit_log/events/_base.html' %} + +{% block content %} + for User {{ event.event_details.updated_user_id }} ({{ event.event_details.updated_user_name }}) + {% if event.event_details["environment"] %} +
+ in Environment {{ event.event_details["environment_id"] }} ({{ event.event_details["environment"] }}) +
+ in Project {{ event.event_details["project_id"] }} ({{ event.event_details["project"] }}) +
+ in Workspace {{ event.event_details["workspace_id"] }} ({{ event.event_details["workspace"] }}) + {% endif %} +{% endblock %} diff --git a/templates/audit_log/events/invitation.html b/templates/audit_log/events/invitation.html new file mode 100644 index 00000000..663670bb --- /dev/null +++ b/templates/audit_log/events/invitation.html @@ -0,0 +1,8 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} + {% set accepted = event.changed_state.status and event.changed_state.status.1 == "ACCEPTED" %} + {% if accepted %} + accepted by {{ event.event_details.email }} (DOD {{ event.event_details.dod_id }}) + {% endif %} +{% endblock %} diff --git a/templates/audit_log/events/project.html b/templates/audit_log/events/project.html new file mode 100644 index 00000000..ef822521 --- /dev/null +++ b/templates/audit_log/events/project.html @@ -0,0 +1,4 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} +{% endblock %} diff --git a/templates/audit_log/events/request.html b/templates/audit_log/events/request.html new file mode 100644 index 00000000..ef822521 --- /dev/null +++ b/templates/audit_log/events/request.html @@ -0,0 +1,4 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} +{% endblock %} diff --git a/templates/audit_log/events/request_review.html b/templates/audit_log/events/request_review.html new file mode 100644 index 00000000..ef822521 --- /dev/null +++ b/templates/audit_log/events/request_review.html @@ -0,0 +1,4 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} +{% endblock %} diff --git a/templates/audit_log/events/request_revision.html b/templates/audit_log/events/request_revision.html new file mode 100644 index 00000000..f29caf62 --- /dev/null +++ b/templates/audit_log/events/request_revision.html @@ -0,0 +1,5 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} + on Request {{ event.request_id }} ({{ event.request.displayname }}) +{% endblock %} diff --git a/templates/audit_log/events/request_status_event.html b/templates/audit_log/events/request_status_event.html new file mode 100644 index 00000000..ef822521 --- /dev/null +++ b/templates/audit_log/events/request_status_event.html @@ -0,0 +1,4 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} +{% endblock %} diff --git a/templates/audit_log/events/user.html b/templates/audit_log/events/user.html new file mode 100644 index 00000000..ef822521 --- /dev/null +++ b/templates/audit_log/events/user.html @@ -0,0 +1,4 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} +{% endblock %} diff --git a/templates/audit_log/events/workspace.html b/templates/audit_log/events/workspace.html new file mode 100644 index 00000000..2d14abad --- /dev/null +++ b/templates/audit_log/events/workspace.html @@ -0,0 +1 @@ +{{ event.resource_type }} diff --git a/templates/audit_log/events/workspace_role.html b/templates/audit_log/events/workspace_role.html new file mode 100644 index 00000000..38a22720 --- /dev/null +++ b/templates/audit_log/events/workspace_role.html @@ -0,0 +1,14 @@ +{% extends "audit_log/events/_base.html" %} + +{% block content %} + for User {{ event.event_details.updated_user_id }} ({{ event.event_details.updated_user_name }}) + in Workspace {{ event.workspace_id }} ({{ event.workspace.name }}) + + {% if event.changed_state.status %} + from status "{{ event.changed_state.status[0] }}" to "{{ event.changed_state.status[1] }}" + {% endif %} + + {% if event.changed_state.role %} + from role {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} + {% endif %} +{% endblock %} From 33546188d5c38ce6e031794b08797d74ef2420ac Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 4 Dec 2018 17:11:21 -0500 Subject: [PATCH 15/19] Refactor to remove repetition --- js/components/selector.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/components/selector.js b/js/components/selector.js index ddc074a6..67f6a30f 100644 --- a/js/components/selector.js +++ b/js/components/selector.js @@ -84,8 +84,9 @@ export default { onShow: function () { setTimeout(() => { // timeout is a hack to make focus work in Chrome - if (this.$refs.choices.find(choice => choice.selected)) { - this.$refs.choices.find(choice => choice.selected).$refs.input[0].focus() + const selected = this.$refs.choices.find(choice => choice.selected) + if (selected) { + selected.$refs.input[0].focus() } else { this.$refs.choices[0].$refs.input[0].focus() } From 1af80843ed397429466f4589597534bed8c326e8 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Wed, 5 Dec 2018 10:36:12 -0500 Subject: [PATCH 16/19] Update default audit event --- templates/audit_log/events/default.html | 49 +++++++++---------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/templates/audit_log/events/default.html b/templates/audit_log/events/default.html index 1fae5e5b..2a6ecdf5 100644 --- a/templates/audit_log/events/default.html +++ b/templates/audit_log/events/default.html @@ -1,39 +1,26 @@ {% extends "audit_log/events/_base.html" %} {% block content %} - {% if event.event_details and event.resource_type == "user" %} - for User {{ event.event_details.updated_user_id }} ({{ event.event_details.updated_user_name }}) - - {% if event.event_details["environment"] %} -
- in Environment {{ event.event_details["environment_id"] }} ({{ event.event_details["environment"] }}) -
- in Project {{ event.event_details["project_id"] }} ({{ event.event_details["project"] }}) -
- in Workspace {{ event.event_details["workspace_id"] }} ({{ event.event_details["workspace"] }}) - {% endif %} -
- - {% elif event.event_details and event.resource_type == "invitation" %} - {% set accepted = event.changed_state.status and event.changed_state.status.1 == "ACCEPTED" %} - {% if accepted %} - accepted by {{ event.event_details.email }} (DOD {{ event.event_details.dod_id }}) - {% endif %} - {% endif %} - - {% if event.changed_state and event.resource_type == 'environment_role' %} - from {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} + {% if event.event_details %}
+ Details: +
+ {% for key, value in event.event_details.items() %} + {% if value is not none %} +
{{ key }}
+
{{ value }}
+ {% endif %} + {% endfor %} +
{% endif %} - - {% if event.workspace %} - in Workspace {{ event.workspace_id }} ({{ event.workspace.name }}) - {% elif event.request %} - on Request {{ event.request_id }} ({{ event.request.displayname }}) - {% endif %} - - {% if event.changed_state.role %} - from {{ event.changed_state.role[0] }} to {{ event.changed_state.role[1] }} + {% if event.changed_state %}
+ Changes: +
+ {% for key, value in event.changed_state.items() %} +
{{ key }}
+
{{ value[0] }} to {{ value[1] }}
+ {% endfor %} +
{% endif %} {% endblock %} From 947e4b682a5ee190ab2981c0ec36a329696c7199 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Wed, 5 Dec 2018 10:50:20 -0500 Subject: [PATCH 17/19] Add simple test for render audit event filter --- tests/test_filters.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/test_filters.py b/tests/test_filters.py index fde37097..6e272b39 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -1,6 +1,7 @@ import pytest -from atst.filters import dollars +from atst.filters import dollars, renderAuditEvent +from atst.models import AuditEvent @pytest.mark.parametrize( @@ -15,3 +16,15 @@ from atst.filters import dollars ) def test_dollar_fomatter(input, expected): assert dollars(input) == expected + + +def test_render_audit_event_with_known_resource_type(): + event = AuditEvent(resource_type='user') + result = renderAuditEvent(event) + assert ' Date: Wed, 5 Dec 2018 10:54:52 -0500 Subject: [PATCH 18/19] Fix linting issues --- atst/filters.py | 4 ++-- tests/test_filters.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/atst/filters.py b/atst/filters.py index f8b8d2d3..32000105 100644 --- a/atst/filters.py +++ b/atst/filters.py @@ -88,11 +88,11 @@ def pageWindow(pagination, size=2): def renderAuditEvent(event): - template_name = 'audit_log/events/{}.html'.format(event.resource_type) + template_name = "audit_log/events/{}.html".format(event.resource_type) try: return render_template(template_name, event=event) except TemplateNotFound: - return render_template('audit_log/events/default.html', event=event) + return render_template("audit_log/events/default.html", event=event) def register_filters(app): diff --git a/tests/test_filters.py b/tests/test_filters.py index 6e272b39..5cfff00e 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -19,12 +19,12 @@ def test_dollar_fomatter(input, expected): def test_render_audit_event_with_known_resource_type(): - event = AuditEvent(resource_type='user') + event = AuditEvent(resource_type="user") result = renderAuditEvent(event) - assert ' Date: Wed, 5 Dec 2018 11:41:35 -0500 Subject: [PATCH 19/19] Update workspace audit event --- templates/audit_log/events/workspace.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/templates/audit_log/events/workspace.html b/templates/audit_log/events/workspace.html index 2d14abad..ef822521 100644 --- a/templates/audit_log/events/workspace.html +++ b/templates/audit_log/events/workspace.html @@ -1 +1,4 @@ -{{ event.resource_type }} +{% extends "audit_log/events/_base.html" %} + +{% block content %} +{% endblock %}