├── .gitignore ├── README.md ├── README_AWS_EKS.md ├── auth └── htpasswd ├── aws-configure-dns.sh ├── aws-create-eks-cluster.sh ├── aws-delete-dns.sh ├── aws-delete-eks-cluster.sh ├── calatrava-configure-dns.sh ├── envrc-template ├── functions.sh ├── install-macos-prereqs.sh ├── install-prereqs.sh ├── kind-with-registry.sh └── setup-tap.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | .idea 3 | 4 | # Temp files generated by scripts 5 | *.yaml 6 | 7 | # Protect against committing secrets 8 | .envrc 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Setting up your own Tanzu Application Platform cluster 2 | 3 | These are scripts that can be used to set up a version of 4 | Tanzu Application Platform (TAP) on your own cluster. 5 | 6 | The process of installing TAP is described in the 7 | [official documentation](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/index.html). 8 | It is not particularly difficult, but you may find that these scripts 9 | save you some time if you just want to get something up and running 10 | quickly. 11 | In particular, they will take care of installing the necessary 12 | pre-requisites and will generate configuration files that you 13 | may later refine if you wish. 14 | 15 | The scripts work on Linux and macOS (and even under WSL on Windows). 16 | They are known to work with: 17 | 18 | * [Minikube](https://minikube.sigs.k8s.io/) on macOS 19 | * [Kind](https://kind.sigs.k8s.io/) on a Linux VM (and at some points, 20 | Docker Desktop on macOS) 21 | * [Amazon EKS](https://aws.amazon.com/eks/) 22 | * [Google GKE](https://cloud.google.com/kubernetes-engine) 23 | 24 | Specific instructions for EKS are in 25 | [README_AWS_EKS.md](README_AWS_EKS.md). 26 | 27 | It may also work (but is less tested) on TCE and TKG. 28 | There are some specific addtional steps for 29 | [TCE](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.0/tap/GUID-install-tce.html) 30 | and 31 | [TKG](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.0/tap/GUID-install-tkg.html) 32 | steps that the setup script does not handle. 33 | It attempts to detect whether it is running against a TCEor TKG cluster 34 | and to notify you of the additional work that needs to be done. 35 | 36 | The script is known to work with DockerHub, Harbor and GCR for the container 37 | registry. 38 | It is also possible to use a completely local registry with 39 | Kind, and that should also be possible (but has not been tested) 40 | with Minikube. 41 | 42 | As far as resources are concerned, from the pre-requisites in the 43 | [the official documentation](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.0/tap/GUID-install-general.html): 44 | 45 | > To deploy all Tanzu Application Platform packages your cluster must 46 | > have at least 8 GB of RAM across all nodes available to Tanzu 47 | > Application Platform. At least 8 CPUs for i9 or equivalent or 12 CPUs 48 | > for i7 or equivalent must be available to Tanzu Application Platform 49 | > components. VMware recommends that at least 16 GB of RAM is available 50 | > to build and deploy applications, including for Kind and Minikube. 51 | 52 | ## What do the scripts do? 53 | 54 | There are three main scripts here: 55 | 56 | * `install-prereqs.sh` (or `install-prereqs-macos.sh` for macOS) 57 | * `kind-with-registry.sh` 58 | * `setup-tap.sh` (with `functions.sh`) 59 | 60 | ### `install-prereqs.sh` 61 | 62 | The first script , `install-prereqs.sh`, installs the necessary CLI tools on 63 | 64-bit AMD/Intel Ubuntu-like Linux systems (including WSL under Windows). 64 | These tools are: 65 | 66 | * `docker`, `kubectl` and `kind`. 67 | * The tools from [carvel.dev](https://carvel.dev) (`ytt`, `kbld`, `kapp`, 68 | `imgpkg` and `vendir`. 69 | * The `kp` [kpack CLI](https://github.com/vmware-tanzu/kpack-cli). 70 | * The `kn` [Knative CLI](https://github.com/knative/client). 71 | * The `tanzu` CLI from the [Tanzu Network](https://network.tanzu.vmware.com/products/tanzu-application-platform/). 72 | 73 | There is an equivalent script for (Intel-based) macOS which uses 74 | the [Brew](https://brew.sh) package manager to install the tools. 75 | 76 | ### `kind-with-registry.sh` 77 | 78 | If you wish to create and use Kind for your Kubernetes environment then 79 | the second script sets up a Kind cluster (named `tap`) which has port 80 | forwarding to ports 80, 443 and 53. 81 | The DNS (port 53) forwarding is probably not necessary but could be used 82 | to hook into the cluster DNS. 83 | The HTTP/S ports will enable applications deployed on TAP via `*.vcap.me` 84 | URLs (all lookups of `vcap.me` addresses resolve to 127.0.0.1). 85 | 86 | The script also creates a local container registry and configures 87 | the cluster to trust it. 88 | 89 | ### `setup-tap.sh` 90 | 91 | The main script is `setup-tap.sh` (which also uses shell functions 92 | defined in `functions.sh`). 93 | 94 | The core part of the TAP installation is actually only a single 95 | command: `tanzu package update --install ...`. 96 | However, most of the work of the setup script is in preparing 97 | the environment for this and in creating the necessary configuration 98 | file(s). 99 | 100 | The script will prompt you for key information (if you have not 101 | set environment variables to supply it automatically) and it 102 | will generate a "sensible" configuration based on the options 103 | that you choose. 104 | 105 | #### Credentials 106 | 107 | You will need a login to the Tanzu Network and access to a Docker 108 | registry (e.g. DockerHub) to which you can push container images. 109 | 110 | The script will prompt you for Tanzu Network and registry credentials, but 111 | you can also set these as environment variables and it will pick them 112 | up automatically. 113 | If set, values will be taken from `TN_USERNAME` and `TN_PASSWORD` for 114 | the Tanzu Network and `REGISTRY`, `REG_USERNAME` and `REG_PASSWORD` for 115 | the registry. 116 | 117 | #### Profiles and packages 118 | 119 | The TAP package supports the concept of installation 120 | profiles, and the script reflects this too. 121 | You can specify that you want to use the 'full' or 'dev' profiles 122 | supported by TAP, when prompted, or set the `INSTALL_PROFILE` 123 | environment variable. 124 | 125 | In addition, you can use the script to do an "unbundled" install 126 | and just pick the packages that you want, for example, just 127 | installing Cloud-Native Runtimes and Tanzu Build Service along 128 | with a basic supply chain. 129 | The script should take care of installing pre-requisite packages in 130 | this case, but this is not thoroughly tested. 131 | 132 | Note that you cannot mix the TAP profiles with the selection of 133 | individual packages that form part of those profiles. 134 | 135 | #### Other information 136 | 137 | The script will also prompt for the location of a catalog file to 138 | use with the TAP GUI as well as the choice of supply chain. 139 | 140 | By default, the script assumes an installation on a local cluster, 141 | such as Kind or Minikube, where services will be accessed via the 142 | `localhost` address. 143 | However, it can also be used for an installation on to a full, 144 | externally-accessible cluster. 145 | In order to enable this you should set the `DOMAIN` environment 146 | variable (or supply a value when prompted) to something other than 147 | the default of `vcap.me`. 148 | 149 | There are further descriptions of the environment variables that 150 | you can use to control the script both in the messages written out 151 | by the script and within the `envrc-template` file. 152 | 153 | After the setup script completes you should have a fully functioning TAP 154 | installation, ready to build and run applications. 155 | 156 | ### Re-running the script 157 | 158 | If the installation fails at any point it should be safe to re-run the setup 159 | script. 160 | If the installation of the main `tap` package fails, but steps prior 161 | to that succeeded, you can re-run the script with the `--skip-init` 162 | option to omit earlier actions that do not have to be re-run. 163 | 164 | ### Use with DockerHub 165 | 166 | Unlike other container registries, DockerHub does not support 167 | hierarchical registry paths. 168 | This means that the initial registry path that you specify, for 169 | example `some-user/tap` will only be the path for the Tanzu Build 170 | Service images. 171 | Any new application created with the build service will appear 172 | as a new registry beneath your user account, for example, 173 | `some-user/my-new-app`. 174 | 175 | ### Use with Google Container Registry (GCR) 176 | 177 | If you intend to use the setup script with a `gcr.io` registry then 178 | you will need an JSON-formatted access key and must use `_json_key` 179 | as the username. 180 | The easiest way to provide the information to the setup script 181 | is to export environment variables, for example, as follows: 182 | 183 | ```bash 184 | export REGISTRY=gcr.io/my-project-name/tap 185 | export REG_USERNAME=_json_key 186 | export REG_PASSWORD="$(cat gcr-access-key.json)" 187 | ``` 188 | 189 | ### Using Amazon EKS 190 | 191 | There are some additional "helper" scripts that you can use to 192 | set up a cluster and configure DNS. 193 | There are described in the [README_AWS_EKS.md](README_AWS_EKS.md) file. 194 | 195 | ### Using Calatrava 196 | 197 | There is some special support for using VMware's private "Calatrava" 198 | environment. 199 | This is primarily to do with the way that Calatrava makes use of 200 | [external DNS](https://github.com/kubernetes-sigs/external-dns). 201 | Some of the configuration is handled in the main setup script, but 202 | you will also need to run the `calatrava-configure-dns.sh` 203 | script if you have deployed the TAP GUI. 204 | 205 | ## Using TAP 206 | 207 | For a local installation, port forwarding will have been set up so that 208 | the GUI should be accessible on http://gui.vcap.me:7000. 209 | 210 | If you used the setup script for Kind that should have caused Docker to 211 | forward traffic so that apps will be accessible on the URL shown 212 | by `tanzu apps workload get ...`, for example: 213 | http://some-app-name.default.apps.vcap.me. 214 | 215 | However, port forwarding will also be set up to port 8080 so that 216 | http://some-app-name.default.apps.vcap.me:8080 should also work if 217 | it wasn't possible to bind to port 80. 218 | 219 | If you deploy to a publicly accessible cluster (not using `vcap.me` as 220 | the domain name) you will need to do the work to map DNS names to the 221 | various load balancers created. 222 | The script will print out these mappings when it completes. 223 | 224 | The TAP components are configured to work with applications deployed primarily in 225 | the `default` namespace. 226 | 227 | You should be able to follow the 228 | [Getting Started guide](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.0/tap/GUID-getting-started.html) 229 | to deploy your first application to the platform. 230 | 231 | -------------------------------------------------------------------------------- /README_AWS_EKS.md: -------------------------------------------------------------------------------- 1 | ## Setting up Tanzu Application Platform on AWS EKS 2 | 3 | These are scripts I've used to set up 4 | Tanzu Application Platform (TAP) on AWS Elastic Kubernetes Service (EKS). 5 | 6 | It is known to work with: 7 | * [TAP beta 4](https://network.tanzu.vmware.com/products/tanzu-application-platform/#/releases/1013926) 8 | * DockerHub for the container registry 9 | 10 | This document assumes you are using a Mac, although it should be adaptable to a Linux-style environment. 11 | 12 | This document and scripts are adapted from the original installation instructions: 13 | 14 | 15 | ### Required environment 16 | 17 | You'll need to have the following: 18 | 19 | * A static domain name (not `nip.io` or similar tools which emulate one) 20 | * An AWS account with an IAM user with the ability to create an EKS cluster with 3 EC2 instances of type `t2.xlarge` 21 | * An external image repository account (e.g. DockerHub) 22 | 23 | You'll need to install a subset of the command line tools as described in the `README.md` file: 24 | * `kubectl` 25 | * `kapp` 26 | * `tanzu` 27 | 28 | You do not need `kind`. 29 | 30 | You'll also need to install: 31 | * the [AWS CLI](https://aws.amazon.com/cli/) 32 | * the [eksctl CLI](https://eksctl.io/) 33 | 34 | ### (Recommended) Set your environment variables 35 | 36 | It is helpful to set the required environment variables in your shell prior to executing the `setup-tap.sh` script, 37 | in order to avoid entering them at the prompts. 38 | 39 | If you use [direnv](https://direnv.net/): 40 | * Copy `envrc-template` to a new file called `.envrc` 41 | * Edit the new file, and `direnv allow` it 42 | 43 | ```bash 44 | cp envrc-template .envrc 45 | # Edit .envrc to contain the correct values. Make sure to use enclose values with shell special characters, like `!`, with single quotes 46 | direnv allow 47 | ``` 48 | Of course, `direnv` is not a requirement - you can use the template file as documentation to set your environment 49 | variables by whatever mechanism you choose. 50 | 51 | AWS-specific notes on environment variables: 52 | * `DOMAIN` should be the FQDN of an AWS Hosted Zone that your user has permission to add records to. 53 | * `APPS_DOMAIN`, `GUI_DOMAIN`, and `EDUCATES_DOMAIN` (if needed based on which packages you select for installation) 54 | should be subdomain of DOMAIN. 55 | 56 | ### Configure (log into) `aws` 57 | 58 | ```bash 59 | aws configure 60 | ``` 61 | Follow the prompts, filling in your AWS IAM's credentials. 62 | 63 | ### Obtain an EKS cluster 64 | 65 | TAP will be installed into an EKS cluster. You can either create a new cluster, or use an existing one. 66 | 67 | #### Option 1: Create an EKS cluster on AWS 68 | 69 | To create a brand-new cluster: 70 | 71 | ```bash 72 | ./aws-create-eks-cluster.sh 73 | ``` 74 | If you have not set all the required environment variables, then you will be prompted for the values. 75 | 76 | If successful, the cluster creation should take approximately 20 minutes. 77 | 78 | Note that this step modifies your `~/.kube/config` file to contain a Kubernetes Context that points to the new cluster, 79 | and also sets the current context to it. You can verify that by typing: 80 | 81 | ``` 82 | kubectl config get-contexts 83 | ``` 84 | 85 | #### Option 2: Use an existing EKS cluster 86 | 87 | To connect to an existing cluster: 88 | 89 | _NOTE_: For instructions on how to grant permissions to a cluster for a new user, 90 | see this: _ 91 | 92 | Navigate the AWS Console Elastic Kubernetes Service page, click on *Clusters*, and find the name of the cluster 93 | you want to install TAP into. Then: 94 | ``` 95 | aws eks update-kubeconfig 96 | ``` 97 | 98 | ### Install TAP in the EKS cluster 99 | 100 | ``` 101 | ./setup-tap.sh 102 | ``` 103 | If you have not set all the required environment variables, then you will be prompted for the values. 104 | 105 | Remember to re-execute the script if it errors out because of timeouts on the first couple tries. 106 | On subsequent runs, to save time, you can (but do not have to) add the `--skip-init` flag, 107 | if the steps prior to installing TAP packages have run. 108 | 109 | The script will output a bunch of useful information upon a successful install. 110 | Keep this in a terminal as it will be useful. 111 | 112 | Sit back and relax ... If successful, the entire installation process should take approximately 20 minutes. 113 | 114 | ### Configure AWS Route 53 DNS records 115 | 116 | This will configure DNS records in an AWS Hosted Zone. 117 | ``` 118 | ./aws-configure-dns.sh 119 | ``` 120 | A caveat about DNS lookup: The DNS entries might take a long time to propagate. 121 | I've had best luck with quick propagation by setting my DNS server to 8.8.8.8 (Google's DNS server). 122 | Also, make sure you are not on a VPN as in this case your locally configured DNS server may not be used. 123 | 124 | ### Use TAP 125 | 126 | NOW you can follow the Getting Started guide from the installation documentation. 127 | 128 | ### (Optional) Re-install TAP 129 | 130 | Delete tap: 131 | ``` 132 | tanzu package installed delete tap -n tap-install 133 | ``` 134 | Then go back to the `./setup-tap.sh` step. 135 | 136 | ### (Optional) Destroy the cluster 137 | 138 | To limit AWS cost, then after deleting your TAP installation, you can destroy the entire AWS EKS cluster. 139 | ``` 140 | ./aws-delete-eks-cluster.sh 141 | ``` 142 | You should also delete the DNS entries, as they are no longer valid: 143 | ``` 144 | ./aws-delete-dns.sh 145 | ``` 146 | 147 | #### Known Issues 148 | 149 | ##### _The AWS cluster fails to delete completely_ 150 | 151 | For example, some AWS objects 152 | (i.e. CloudFormation) might not delete. In this case you will need to use the AWS Console to find 153 | the orphaned objects and delete them manually. This can be a tedious task. 154 | 155 | **More details:** 156 | 157 | If the `aws-delete-eks-cluster.sh` script reports success, but you cannot re-create the cluster again 158 | with the same name, and the error message indicates there is an existing stack (or service) of the name the script is 159 | trying to create: 160 | 1. Give it a couple minutes. It might be still in-process of deletion. 161 | 2. If the error persists, the probable cause is that some resources associated with the deleted cluster 162 | have been orphaned. In order to re-create the cluster with the same name, they need to be deleted. 163 | 164 | The following steps use the AWS console (console.aws.com). 165 | 166 | First, find the VPC associated with the cluster you previously deleted: 167 | Go to AWS console / VPCs / Your VPCs. You can identify the target VPC by name. 168 | Make a note of its ID, as it will be useful in identifying other objects to delete. 169 | 170 | The following additional steps are in order of the dependencies, so they should work most of the time. 171 | Your Mileage May Vary! 172 | If you have trouble, the general strategy is: delete resources from the bottom up in the dependency hierarchy. 173 | The AWS Console will _sometimes_ give you hints. 174 | 175 | 1. Try to delete LoadBalancers: Go to AWS console / EC2, and select Load Balancers on the left. 176 | Identify the Load Balancers with the VPC ID you noted above, and try to delete them. 177 | 178 | 2. Try to delete VPCs: Go to AWS console / VPCs / Your VPCs. Identify the VPC to delete. Delete it. 179 | 180 | 3. Try to delete CloudFormation instances: Go to AWS console / Cloud Formation. 181 | Find the stacks that were associated with your cluster. You should be able to identify them by name. 182 | They will also have a tag with key = `eksctl.cluster.k8s.io/v1alpha1/cluster-name`, value = `cluster name` 183 | 184 | Try to delete them. If there are two stacks and one of them is the worker-nodes stack, delete that one first. 185 | 186 | -------------------------------------------------------------------------------- /auth/htpasswd: -------------------------------------------------------------------------------- 1 | admin:$2y$05$BxTMV67dKTRvC994WfRDoeGtvlhTLF4YThurkAHol2qazQNh7NLfe 2 | -------------------------------------------------------------------------------- /aws-configure-dns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$(dirname $0)/functions.sh" 3 | 4 | set -e 5 | set -x 6 | findOrPrompt DOMAIN "Root Domain" 7 | cat << EOF 8 | 9 | >>> NOTE: The following domains should be subdomains of $DOMAIN. 10 | 11 | EOF 12 | findOrPromptWithDefault GUI_DOMAIN "UI Domain" "gui.${DOMAIN}" 13 | findOrPromptWithDefault APPS_DOMAIN "Applications root domain" "apps.${DOMAIN}" 14 | findOrPromptWithDefault EDUCATES_DOMAIN "Learning Center domain" "learn.${DOMAIN}" 15 | 16 | function createDnsRecord { 17 | fqdn=$1 18 | resource_type=$2 19 | resource_name=$3 20 | namespace=$4 21 | 22 | elb_hostname=$(kubectl get "$resource_type/$resource_name" -n "$namespace" -o json 2>/dev/null| jq '.status.loadBalancer.ingress[0].hostname'|sed 's/\"//g') 23 | if [[ "$elb_hostname" == "" || "$elb_hostname" == "null" ]] 24 | then 25 | echo "Will not create DNS entry for $fqdn" 26 | return 27 | fi 28 | 29 | echo "Creating DNS entry for $fqdn, hostname=$elb_hostname" 30 | 31 | elb_zone_id=$(aws elb describe-load-balancers| jq --arg DNSNAME "${elb_hostname}" '.LoadBalancerDescriptions[] | select( .DNSName == $DNSNAME ) | .CanonicalHostedZoneNameID ' | sed s/\"//g) 32 | file="$fqdn.json" 33 | cat > "$file" << EOF 34 | { 35 | "Comment": "Creating $fqdn Alias resource record sets in Route 53", 36 | "Changes": [ 37 | { 38 | "Action": "UPSERT", 39 | "ResourceRecordSet": { 40 | "Name": "$fqdn", 41 | "Type": "A", 42 | "AliasTarget": { 43 | "HostedZoneId": "$elb_zone_id", 44 | "DNSName": "dualstack.$elb_hostname", 45 | "EvaluateTargetHealth": false 46 | } 47 | } 48 | } 49 | ] 50 | } 51 | EOF 52 | aws route53 change-resource-record-sets --hosted-zone-id ${zone_id} --change-batch "file://$file" 53 | } 54 | 55 | zone_id=$(aws route53 list-hosted-zones|jq --arg DOMAIN "${DOMAIN}." '.HostedZones[] | select( .Name == $DOMAIN ) | .Id'| sed 's/\/hostedzone\///g'|sed 's/\"//g') 56 | if [[ $? -ne 0 || "$zone_id" == "" ]] 57 | then 58 | echo "Unable to extract host zone ID. Exiting." 59 | exit 1 60 | fi 61 | 62 | createDnsRecord "*.$APPS_DOMAIN" service envoy tanzu-system-ingress 63 | 64 | createDnsRecord "*.$EDUCATES_DOMAIN" ingress learningcenter-portal learning-center-guided-ui 65 | 66 | createDnsRecord "$GUI_DOMAIN" service server tap-gui 67 | 68 | kubectl patch cm/config-domain -n knative-serving -p "{ \"data\": null }" 69 | kubectl patch cm/config-domain -n knative-serving -p "{ \"data\": { \"$APPS_DOMAIN\": \"\" } }" 70 | -------------------------------------------------------------------------------- /aws-create-eks-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit # set -e 3 | set -o pipefail 4 | 5 | ## FROM: https://www.youtube.com/watch?v=p6xDCz00TxU, the pertinent stuff starting at approx. 6:26 6 | 7 | function findOrPrompt() { 8 | local varName="$1" 9 | local prompt="$2" 10 | 11 | if [[ -z "${!varName}" ]] 12 | then 13 | read -p "$prompt: " $varName 14 | else 15 | echo "Value for $varName found in environment" 16 | fi 17 | } 18 | 19 | findOrPrompt AWS_REGION "AWS region" 20 | findOrPrompt EKS_CLUSTER_NAME "EKS cluster name (choose a name)" 21 | 22 | set -x 23 | 24 | k8s_version=1.21 25 | instance_type=t2.xlarge # 4 CPUs, 16G RAM, 80G storage per node. I think this is among the smallest types that will support EKS. 26 | node_count=3 # 1 is too few, 3 works. Not tried 2. 27 | 28 | eksctl create cluster \ 29 | --name "$EKS_CLUSTER_NAME" \ 30 | --version "$k8s_version" \ 31 | --region "$AWS_REGION" \ 32 | --nodegroup-name worker-nodes \ 33 | --node-type "$instance_type" \ 34 | --nodes "$node_count" 35 | -------------------------------------------------------------------------------- /aws-delete-dns.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ndwinton/tap-setup-scripts/98b686164da432b11048e96e2478b9d8c9c262c8/aws-delete-dns.sh -------------------------------------------------------------------------------- /aws-delete-eks-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | set -o pipefail 4 | script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | source "$script_dir/functions.sh" 6 | 7 | if [[ -n "$1" ]] 8 | then 9 | EKS_CLUSTER_NAME=$1 10 | fi 11 | 12 | findOrPrompt AWS_REGION "AWS REGION" 13 | findOrPrompt EKS_CLUSTER_NAME "EKS cluster name (the name of the existing cluster)" 14 | 15 | eksctl delete cluster --name "$EKS_CLUSTER_NAME" --region "$AWS_REGION" 16 | 17 | while [[ "$(eksctl get cluster "$EKS_CLUSTER_NAME" 2>&1 || true)" != *"No cluster found"* ]] 18 | do 19 | message "Waiting for cluster $EKS_CLUSTER_NAME to be nonexistent ..." 20 | sleep 5 21 | done 22 | -------------------------------------------------------------------------------- /calatrava-configure-dns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$(dirname $0)/functions.sh" 3 | 4 | set -e 5 | 6 | function enableExternalDns { 7 | banner "Enabling External DNS" 8 | 9 | kubectl apply -f \ 10 | https://raw.githubusercontent.com/kubernetes-sigs/external-dns/v0.7.1/docs/contributing/crd-source/crd-manifest.yaml 11 | } 12 | 13 | function createDnsRecord { 14 | local fqdn="$1" 15 | local service="$2" 16 | local namespace="$3" 17 | 18 | banner "Creating DNS record for $fqdn" 19 | 20 | local ip=$(kubectl get -n $namespace service $service -o jsonpath='{$.status.loadBalancer.ingress[0].ip}') 21 | 22 | if [[ "$ip" == "" ]] 23 | then 24 | message "Can't find IP address for service '$service' in namespace '$namespace'" 25 | return 26 | fi 27 | 28 | kubectl apply -f- <.calatrava.vmware.com, 53 | which is the default behaviour of the setup.sh script. 54 | 55 | EOF 56 | 57 | findOrPrompt DOMAIN "Root Domain" 58 | findOrPromptWithDefault GUI_DOMAIN "UI Domain" "gui.${DOMAIN}" 59 | 60 | if [[ "$DOMAIN" != *.calatrava.vmware.com ]] || [[ "$GUI_DOMAIN" != *.calatrava.vmware.com ]] 61 | then 62 | message "This script can only be used to set up DNS within the calatrava.vmware.com domain" 63 | exit 1 64 | fi 65 | 66 | enableExternalDns 67 | 68 | createDnsRecord "$GUI_DOMAIN" server tap-gui 69 | 70 | -------------------------------------------------------------------------------- /envrc-template: -------------------------------------------------------------------------------- 1 | ### TanzuNet credentials 2 | export TN_USERNAME=user@example.com 3 | export TN_PASSWORD='password with a special character that requires single quotes!' 4 | 5 | ### External image repo (e.g. DockerHub) details 6 | # DockerHub requires the format username/registry. Other registries, 7 | # such as Harbor are different and likely to be of the form 8 | # my.repo.host/my-project/my-registry 9 | export REGISTRY=user/tap 10 | export REG_USERNAME=username 11 | export REG_PASSWORD=password 12 | ### For GCR use something like this: 13 | # export REGISTRY=gcr.io/my-project/tap 14 | # export REG_USERNAME=_json_key # Exactly this value 15 | # export REG_PASSWORD="$(cat gcr-access-key.json)" # A service account key 16 | 17 | ### Installation configuration 18 | 19 | # INFRASTRUCTURE_PROVIDER - What kind of K8s infrastructure is used? 20 | # The script will attempt to work this out, so you can leave it blank. 21 | # If there are problems, however, possible values are: aws, google, vsphere 22 | # kind and minikube. 23 | # This primarily affects how the Contour ingress controller is exposed. 24 | # For aws and google a LoadBalancer is used, otherwise it defaults to 25 | # NodePort. In the case of AWS, it uses a "classic" load balancer. 26 | export INFRASTRUCTURE_PROVIDER= 27 | 28 | # INSTALL_PROFILE 29 | # Either one of 'full' or 'light' or a space-separated list of individual 30 | # (short-form) package names 31 | export INSTALL_PROFILE=full 32 | 33 | # EXCLUDED_PACKAGES 34 | # If using 'full' or 'light' profiles, this is a space-separated 35 | # list of packages NOT to include (or 'none' if there are no 36 | # packages to exclude). 37 | export EXCLUDED_PACKAGES=none 38 | 39 | # SUPPLY_CHAIN and EXTRA_SUPPLY_CHAIN 40 | # The choice of primary supply chain. Valid values are: none, basic, 41 | # testing, or scanning. 42 | # It is also possible to install a second supply chain, as long as 43 | # they use different workload selectors. 44 | export SUPPLY_CHAIN=basic 45 | export EXTRA_SUPPLY_CHAIN=testing 46 | 47 | # The DOMAIN must be a static URL which does not change with the 48 | # underlying IP or LoadBalancer. This means you cannot use clever 49 | # DNS mapping sites such as 'nip.io' if these values will change. 50 | # 51 | # NOTE: Setting DOMAIN to 'vcap.me' (which resolves to 127.0.0.1) 52 | # indicates that this is a purely local installation. 53 | export DOMAIN=example.com 54 | # GUI_DOMAIN is only needed if the tap-gui package is selected for 55 | # installation, either directly or as part of the full or dev profiles. 56 | # NOTE: This is served on port 7000 57 | export GUI_DOMAIN="gui.$DOMAIN" 58 | # APPS_DOMAIN is the sub-domain under which all apps will be deployed 59 | export APPS_DOMAIN="apps.$DOMAIN" 60 | # EDUCATES_DOMAIN is only needed if learningcenter package is selected 61 | # for installation 62 | export EDUCATES_DOMAIN="learn.$DOMAIN" 63 | 64 | # GUI_CATALOG_URL 65 | # The GUI needs a (blank) catalog to present. 66 | export GUI_CATALOG_URL=https://github.com/your-registry/tap-blank-catalog/blob/main/catalog-info.yaml 67 | 68 | ### AWS values, OK to omit if you are not installing on AWS 69 | export AWS_REGION=us-east-2 # Pick a region. 70 | export EKS_CLUSTER_NAME=my-aws-eks-cluster # Human-friendly name of EKS cluster, available in AWS Console. 71 | -------------------------------------------------------------------------------- /functions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | function banner { 5 | local line 6 | echo "" 7 | echo "###" 8 | for line in "$@" 9 | do 10 | echo "### $line" 11 | done 12 | echo "###" 13 | echo "" 14 | } 15 | 16 | function message { 17 | local line 18 | for line in "$@" 19 | do 20 | echo ">>> $line" 21 | done 22 | } 23 | 24 | function fatal { 25 | message "ERROR: $*" 26 | exit 1 27 | } 28 | 29 | function findOrPrompt { 30 | local varName="$1" 31 | local prompt="$2" 32 | local secret=${3-false} 33 | 34 | if [[ -z "${!varName}" ]] 35 | then 36 | echo "$varName not found in environment" 37 | read -p "$prompt: " $varName 38 | elif $secret 39 | then 40 | echo "Value for $varName found in environment: " 41 | else 42 | echo "Value for $varName found in environment: ${!varName}" 43 | fi 44 | } 45 | 46 | function findOrPromptWithDefault { 47 | local varName="$1" 48 | local prompt="$2" 49 | local default="$3" 50 | 51 | findOrPrompt "$varName" "$prompt [$default]" 52 | if [[ -z "${!varName}" ]] 53 | then 54 | export ${varName}="$default" 55 | fi 56 | } 57 | 58 | function requireValue { 59 | local varName 60 | 61 | for varName in $* 62 | do 63 | if [[ -z "${!varName}" ]] 64 | then 65 | fatal "Variable $varName is missing at line $(caller)" 66 | fi 67 | done 68 | } 69 | 70 | # Get the latest version of a package 71 | function latestVersion() { 72 | tanzu package available list $1 -n tap-install -o json | \ 73 | jq -r 'sort_by(."released-at")[-1].version' 74 | } 75 | 76 | # Wait until there is no (non-error) output from a command 77 | function waitForRemoval() { 78 | while [[ -n $("$@" 2> /dev/null || true) ]] 79 | do 80 | message "Waiting for resource to disappear ..." 81 | sleep 5 82 | done 83 | } 84 | 85 | # Updates or installs the latest version of a package 86 | function installLatest() { 87 | local name=$1 88 | local package=$2 89 | local values=$3 90 | local timeout=${4:-10m} 91 | 92 | local version=$(latestVersion $package) 93 | 94 | logRun tanzu package installed update --install \ 95 | $name -p $package -v $version \ 96 | -n tap-install \ 97 | --poll-timeout $timeout \ 98 | ${values:+-f} $values 99 | 100 | tanzu package installed get $name -n tap-install 101 | } 102 | 103 | function logRun() { 104 | message "Running: $*" 105 | "$@" 106 | } 107 | 108 | function isLocal() { 109 | requireValue DOMAIN 110 | 111 | [[ $DOMAIN == "vcap.me" ]] 112 | } 113 | 114 | function deployKappAndSecretgenControllers { 115 | checkForTCETKG 116 | 117 | banner "Downloading kapp + secretgen configuration bundle" 118 | 119 | export IMGPKG_USERNAME="$TN_USERNAME" 120 | export IMGPKG_PASSWORD="$TN_PASSWORD" 121 | 122 | local tag=$(imgpkg tag list -i registry.tanzu.vmware.com/tanzu-cluster-essentials/cluster-essentials-bundle --json | \ 123 | jq -r '.Tables[0].Rows[].name' | \ 124 | sed -ne '/image-locations/{ 125 | s/\.image-locations.*$// 126 | s/-/:/ 127 | p 128 | }' | tail -n 1) 129 | local bundle="registry.tanzu.vmware.com/tanzu-cluster-essentials/cluster-essentials-bundle@${tag}" 130 | 131 | rm -rf ./bundle 132 | imgpkg pull -b $bundle -o ./bundle/ 133 | 134 | export YTT_registry__server=registry.tanzu.vmware.com 135 | export YTT_registry__username="$TN_USERNAME" 136 | export YTT_registry__password="$TN_PASSWORD" 137 | 138 | message "Creating namespace $ns_name" 139 | 140 | local ns_name=tanzu-cluster-essentials 141 | (kubectl get ns $ns_name 2> /dev/null) || \ 142 | kubectl create ns $ns_name 143 | 144 | banner "Deploying kapp-controller" 145 | 146 | ytt -f ./bundle/kapp-controller/config/ -f ./bundle/registry-creds/ --data-values-env YTT --data-value-yaml kappController.deployment.concurrency=10 \ 147 | | kbld -f- -f ./bundle/.imgpkg/images.yml \ 148 | | kapp deploy -a kapp-controller -n $ns_name -f- --yes 149 | 150 | kubectl get deployment kapp-controller -n kapp-controller -o yaml | grep kapp-controller.carvel.dev/version: 151 | 152 | banner "Deploying secretgen-controller" 153 | ytt -f ./bundle/secretgen-controller/config/ -f ./bundle/registry-creds/ --data-values-env YTT \ 154 | | kbld -f- -f ./bundle/.imgpkg/images.yml \ 155 | | kapp deploy -a secretgen-controller -n $ns_name -f- --yes 156 | 157 | kubectl get deployment secretgen-controller -n secretgen-controller -o yaml | grep secretgen-controller.carvel.dev/version: 158 | } 159 | 160 | function checkForTCETKG { 161 | if kubectl get deployment kapp-controller -n tkg-system 2> /dev/null 162 | then 163 | banner "You appear to be running on a TCE or TKG cluster." \ 164 | "You must follow the instructions in the documentation to delete the current" \ 165 | "kapp-controller deployment before re-running this script." \ 166 | "" \ 167 | "The documentation for TCE is at:" \ 168 | "https://docs.vmware.com/en/Tanzu-Application-Platform/0.4/tap/GUID-install-tce.html" \ 169 | "" \ 170 | "The documentation for TKG is at:" \ 171 | "https://docs.vmware.com/en/Tanzu-Application-Platform/0.4/tap/GUID-install-tkg.html" 172 | 173 | fatal "Cannot continue" 174 | fi 175 | } 176 | 177 | function deployKappController() { 178 | banner "Deploying kapp-controller" 179 | 180 | # Check if we appear to be running on TCE or TKG. 181 | # If so, there will need to be some manual steps taken to delete the 182 | # existing kapp-controller 183 | 184 | if kubectl get deployment kapp-controller -n tkg-system 2> /dev/null 185 | then 186 | banner "You appear to be running on a TCE or TKG cluster." \ 187 | "You must follow the instructions in the documentation to delete the current" \ 188 | "kapp-controller deployment before re-running this script." \ 189 | "" \ 190 | "The documentation for TCE is at:" \ 191 | "https://docs.vmware.com/en/Tanzu-Application-Platform/0.4/tap/GUID-install-tce.html" \ 192 | "" \ 193 | "The documentation for TKG is at:" \ 194 | "https://docs.vmware.com/en/Tanzu-Application-Platform/0.4/tap/GUID-install-tkg.html" 195 | 196 | fatal "Cannot continue" 197 | fi 198 | 199 | kapp deploy -a kc -f https://github.com/vmware-tanzu/carvel-kapp-controller/releases/latest/download/release.yml -y 200 | kubectl get deployment kapp-controller -n kapp-controller -o yaml | grep kapp-controller.carvel.dev/version: 201 | } 202 | 203 | function createTapNamespace() { 204 | 205 | banner "Creating tap-install namespace" 206 | 207 | (kubectl get ns tap-install 2> /dev/null) || \ 208 | kubectl create ns tap-install 209 | } 210 | 211 | function createTapRegistrySecret { 212 | requireValue TN_USERNAME TN_PASSWORD 213 | 214 | banner "Creating tap-registry registry secret" 215 | 216 | tanzu secret registry delete tap-registry --namespace tap-install -y || true 217 | waitForRemoval kubectl get secret tap-registry --namespace tap-install -o json 218 | 219 | tanzu secret registry add tap-registry \ 220 | --username "$TN_USERNAME" --password "$TN_PASSWORD" \ 221 | --server registry.tanzu.vmware.com \ 222 | --export-to-all-namespaces --namespace tap-install --yes 223 | } 224 | 225 | function loadPackageRepository { 226 | requireValue TAP_VERSION 227 | 228 | banner "Removing any current TAP package repository" 229 | 230 | tanzu package repository delete tanzu-tap-repository -n tap-install --yes || true 231 | waitForRemoval tanzu package repository get tanzu-tap-repository -n tap-install -o json 232 | 233 | banner "Adding TAP package repository" 234 | 235 | tanzu package repository add tanzu-tap-repository \ 236 | --url registry.tanzu.vmware.com/tanzu-application-platform/tap-packages:$TAP_VERSION \ 237 | --namespace tap-install 238 | tanzu package repository get tanzu-tap-repository --namespace tap-install 239 | while [[ $(tanzu package available list --namespace tap-install -o json) == '[]' ]] 240 | do 241 | message "Waiting for packages ..." 242 | sleep 5 243 | done 244 | } 245 | 246 | function embedYaml { 247 | local file="$1" 248 | local indent="${2- }" 249 | cat $file | sed -e "/^---/d; s/^/$indent/;" 250 | } 251 | 252 | declare -A ENABLED 253 | 254 | function isEnabled { 255 | local profile 256 | 257 | for profile in $* 258 | do 259 | if ${ENABLED[$profile]:-false} 260 | then 261 | return 0 262 | fi 263 | done 264 | return 1 265 | } 266 | 267 | function validateAndEnableInstallationOptions { 268 | local value 269 | 270 | requireValue INSTALL_PROFILE 271 | 272 | for value in $INSTALL_PROFILE 273 | do 274 | case $value in 275 | accelerator) ;; 276 | api-portal) ;; 277 | appliveview) ;; 278 | buildservice) ;; 279 | cartographer) ;; 280 | cnrs) ;; 281 | conventions-controller) ;; 282 | convention-controller) ;; # Alias for above 283 | dev) 284 | message "WARNING: The 'dev' profile has been replaced by 'light' -- assuming 'light'" 285 | value=light 286 | ;; 287 | developer-conventions) ;; 288 | full) ;; 289 | image-policy-webhook) ;; 290 | grype) ;; 291 | learningcenter) ;; 292 | learningcenter-workshops) ;; 293 | light) ;; 294 | ootb-supply-chain-basic) ;; 295 | ootb-supply-chain-testing) ;; 296 | ootb-supply-chain-testing-scanning) ;; 297 | ootb-templates) ;; 298 | scanning) ;; 299 | service-bindings) ;; 300 | services-toolkit) ;; 301 | signing) ;; 302 | source-controller) ;; 303 | spring-boot-conventions) ;; 304 | tap-gui) ;; 305 | tbs) ;; 306 | tekton) ;; 307 | *) 308 | fatal "Invalid INSTALL_PROFILE component: $value" 309 | ;; 310 | esac 311 | 312 | ENABLED[$value]=true 313 | done 314 | 315 | if isEnabled full light && [[ ${#ENABLED[*]} != 1 ]] 316 | then 317 | fatal "'full' and 'light' must not be mixed with any other installation profiles" 318 | fi 319 | return 0 320 | } 321 | 322 | function validateAndEnableSupplyChainComponent { 323 | requireValue SUPPLY_CHAIN 324 | 325 | validateExtraSupplyChain 326 | 327 | case $SUPPLY_CHAIN in 328 | basic|testing|scanning) 329 | isEnabled full light && return 0 330 | ;; 331 | none) 332 | if isEnabled full light 333 | then 334 | message "Supply chain type cannot be 'none' for 'full' or 'light' profiles -- using 'basic'" 335 | SUPPLY_CHAIN='basic' 336 | return 0 337 | fi 338 | ;; 339 | *) 340 | fatal "Invalid supply-chain value: $SUPPLY_CHAIN" 341 | ;; 342 | esac 343 | 344 | case $SUPPLY_CHAIN in 345 | basic) 346 | ENABLED[ootb-supply-chain-basic]=true 347 | ;; 348 | testing) 349 | ENABLED[ootb-supply-chain-testing]=true 350 | ;; 351 | scanning) 352 | ENABLED[ootb-supply-chain-testing-scanning]=true 353 | ;; 354 | esac 355 | 356 | return 0 357 | } 358 | 359 | function validateExtraSupplyChain { 360 | requireValue SUPPLY_CHAIN EXTRA_SUPPLY_CHAIN 361 | 362 | if [[ "$SUPPLY_CHAIN" == "$EXTRA_SUPPLY_CHAIN" ]] 363 | then 364 | EXTRA_SUPPLY_CHAIN="none" 365 | fi 366 | 367 | case $EXTRA_SUPPLY_CHAIN in 368 | testing) 369 | if [[ "$SUPPLY_CHAIN" == "scanning" || "$SUPPLY_CHAIN" == "testing_scanning" ]] 370 | then 371 | fatal "Cannot enable both 'testing' and 'scanning' supply chains" 372 | fi 373 | ;; 374 | scanning|testing_scanning) 375 | if [[ "$SUPPLY_CHAIN" == "testing" ]] 376 | then 377 | fatal "Cannot enable both 'testing' and 'scanning' supply chains" 378 | fi 379 | ;; 380 | none|basic) 381 | : no-op 382 | ;; 383 | *) 384 | fatal "Invalid extra supply chain: $EXTRA_SUPPLY_CHAIN" 385 | ;; 386 | esac 387 | } 388 | 389 | function enableExtraSupplyChain { 390 | requireValue EXTRA_SUPPLY_CHAIN 391 | 392 | case $EXTRA_SUPPLY_CHAIN in 393 | basic) 394 | ENABLED[ootb-supply-chain-basic]=true 395 | ;; 396 | testing) 397 | ENABLED[ootb-supply-chain-testing]=true 398 | ;; 399 | scanning|testing_scanning) 400 | ENABLED[ootb-supply-chain-testing-scanning]=true 401 | ;; 402 | esac 403 | } 404 | 405 | function configureExtraSupplyChain { 406 | validateExtraSupplyChain 407 | enableExtraSupplyChain 408 | configureOotbSupplyChains 409 | } 410 | 411 | declare -A PRE_REQ 412 | PRE_REQ[accelerator]="source-controller" 413 | PRE_REQ[appliveview]="conventions-controller" 414 | PRE_REQ[cartographer]="source-controller" 415 | PRE_REQ[developer-conventions]="conventions-controller" 416 | PRE_REQ[learningcenter-workshops]="learningcenter" 417 | PRE_REQ[ootb-templates]="conventions-controller cartographer ${PRE_REQ[cartographer]}" 418 | PRE_REQ[ootb-supply-chain-basic]="ootb-templates ${PRE_REQ[ootb-templates]}" 419 | PRE_REQ[ootb-supply-chain-testing]="tekton ootb-templates ${PRE_REQ[ootb-templates]}" 420 | PRE_REQ[ootb-supply-chain-testing-scanning]="tekton scanning ootb-templates ${PRE_REQ[ootb-templates]}" 421 | PRE_REQ[scanning]="grype" 422 | PRE_REQ[grype]="scanning" 423 | PRE_REQ[service-bindings]="services-toolkit" 424 | PRE_REQ[services-toolkit]="service-bindings" 425 | PRE_REQ[spring-boot-conventions]="conventions-controller" 426 | 427 | function enablePreRequisites { 428 | local initial=${!ENABLED[*]} 429 | local package 430 | 431 | for package in $initial 432 | do 433 | for preReq in ${PRE_REQ[$package]} 434 | do 435 | ENABLED[$preReq]=true 436 | done 437 | done 438 | } 439 | 440 | function createIfNeeded { 441 | local file="$1" 442 | requireValue RECREATE_CONFIG 443 | 444 | if [[ ! -e $file ]] || $RECREATE_CONFIG 445 | then 446 | cat > $file 447 | else 448 | message "Re-using existing file: $file" 449 | fi 450 | } 451 | 452 | function appendIfNeeded { 453 | local file="$1" 454 | requireValue RECREATE_CONFIG 455 | 456 | if [[ ! -e $file ]] || $RECREATE_CONFIG 457 | then 458 | cat >> $file 459 | else 460 | message "Re-using existing file: $file" 461 | fi 462 | } 463 | 464 | function configureCertManager { 465 | if ! isEnabled full light 466 | then 467 | banner "Installing Cert Manager" 468 | 469 | createIfNeeded cert-manager-rbac.yaml < /dev/null || true 839 | waitForRemoval kubectl get secret image-pull-secret -n image-policy-system -o json 840 | kubectl create secret docker-registry image-pull-secret \ 841 | --docker-server="$REG_HOST" \ 842 | --docker-username="$REG_USERNAME" \ 843 | --docker-password="$REG_PASSWORD" \ 844 | --namespace image-policy-system 845 | 846 | cat < /dev/null || true 885 | kubectl delete pod busybox --force --grace-period=0 2> /dev/null || true 886 | 887 | message "The cosign pod should be created without a warning" 888 | kubectl run cosign --image=gcr.io/projectsigstore/cosign:v1.2.1 --restart=Never --command -- sleep 5 889 | 890 | message "The busybox pod should generate a warning" 891 | kubectl run busybox --image=busybox --restart=Never -- sleep 5 892 | 893 | kubectl delete pod cosign --force --grace-period=0 2> /dev/null || true 894 | kubectl delete pod busybox --force --grace-period=0 2> /dev/null || true 895 | fi 896 | } 897 | 898 | function configureScanning { 899 | 900 | createIfNeeded scst-grype-values.yaml < /dev/null | jq -r .serverVersion.gitVersion)" in 958 | *-gke.*) 959 | echo "google" 960 | ;; 961 | *-eks-*) 962 | echo "aws" 963 | ;; 964 | *) 965 | if kubectl get ds -n kube-system -o name | grep -q kindnet 966 | then 967 | echo "kind" 968 | elif kubectl get pod -n kube-system -o name | grep -q minikube 969 | then 970 | echo "minikube" 971 | elif [[ "$DOMAIN" == *.calatrava.vmware.com ]] 972 | then 973 | echo "calatrava" 974 | else 975 | echo "unknown" 976 | fi 977 | ;; 978 | esac 979 | } 980 | 981 | function configureContour { 982 | requireValue CONTOUR_SERVICE_TYPE 983 | 984 | case $(infrastructureProvider) in 985 | aws) 986 | createIfNeeded contour-values.yaml <> tap-values.yaml 1218 | for package in $EXCLUDED_PACKAGES 1219 | do 1220 | for fullPackage in ${FULL_PACKAGE[$package]:-$package} 1221 | do 1222 | echo "- $fullPackage" >> tap-values.yaml 1223 | done 1224 | done 1225 | fi 1226 | } 1227 | 1228 | function hostIp { 1229 | # This works on both macOS and Linux 1230 | ifconfig -a | awk '/^(en|wl)/,/(inet |status|TX error)/ { if ($1 == "inet") { print $2; exit; } }' 1231 | } 1232 | 1233 | function latestPublicTapVersion { 1234 | curl -s https://network.tanzu.vmware.com/api/v2/products/tanzu-application-platform/releases | \ 1235 | jq -r '.releases | sort_by(.release_date)[-1].version' 1236 | } 1237 | -------------------------------------------------------------------------------- /install-macos-prereqs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat <>> $line" 30 | done 31 | echo "" 32 | } 33 | 34 | if [[ "$(uname -s)/$(uname -m)" != "Darwin/x86_64" ]] 35 | then 36 | log "Sorry, this script only handles macOS x86_64 systems" 37 | exit 1 38 | fi 39 | 40 | log "Installing basic tools" 41 | 42 | brew install jq 43 | 44 | if which docker > /dev/null 45 | then 46 | log "Using current Docker installation" 47 | else 48 | log "You can use either Docker Desktop or docker-machine" \ 49 | "This script will install the docker CLI and docker-machine" 50 | brew install docker docker-machine 51 | fi 52 | 53 | DOWNLOADS=/tmp/downloads 54 | mkdir -p $DOWNLOADS 55 | 56 | log "Installing kubectl" 57 | 58 | brew install kubectl 59 | 60 | log "Installing kind" 61 | 62 | brew install kind 63 | 64 | log "Installing carvel tools" 65 | 66 | brew tap vmware-tanzu/carvel 67 | brew install ytt kbld kapp imgpkg kwt vendir 68 | 69 | log "Installing kn" 70 | 71 | brew install kn 72 | 73 | log "Installing kp" 74 | 75 | curl -Lo $DOWNLOADS/kp https://github.com/vmware-tanzu/kpack-cli/releases/download/v0.4.2/kp-darwin-0.4.2 76 | sudo install -m 0755 $DOWNLOADS/kp /usr/local/bin/kp 77 | 78 | log "Installing pivnet CLI" 79 | 80 | curl -Lo $DOWNLOADS/pivnet https://github.com/pivotal-cf/pivnet-cli/releases/download/v3.0.1/pivnet-darwin-amd64-3.0.1 81 | sudo install -m 0755 $DOWNLOADS/pivnet /usr/local/bin/pivnet 82 | 83 | log "Installing tanzu CLI" 84 | 85 | read -p 'Tanzu Network UAA Refresh Token: ' PIVNET_TOKEN 86 | pivnet login --api-token="$PIVNET_TOKEN" 87 | 88 | ESSENTIALS_VERSION=$(pivnet releases -p tanzu-cluster-essentials --format=json | \ 89 | jq -r 'sort_by(.updated_at)[-1].version') 90 | 91 | log "Latest Tanzu Cluster Essentials release found is $ESSENTIALS_VERSION" 92 | 93 | ESSENTIALS_FILE_NAME=tanzu-cluster-essentials-darwin-amd64-$ESSENTIALS_VERSION.tgz 94 | ESSENTIALS_FILE_ID=$(pivnet product-files \ 95 | -p tanzu-cluster-essentials \ 96 | -r $ESSENTIALS_VERSION \ 97 | --format=json | jq '.[] | select(.name == "'$ESSENTIALS_FILE_NAME'").id' ) 98 | 99 | pivnet download-product-files \ 100 | --download-dir $DOWNLOADS \ 101 | --product-slug='tanzu-cluster-essentials' \ 102 | --release-version=$ESSENTIALS_VERSION \ 103 | --product-file-id=$ESSENTIALS_FILE_ID 104 | 105 | TAP_VERSION=$(pivnet releases -p tanzu-application-platform --format=json | \ 106 | jq -r 'sort_by(.updated_at)[-1].version') 107 | 108 | log "Latest TAP release found is $TAP_VERSION" 109 | 110 | FILE_ID=$(pivnet product-files \ 111 | -p tanzu-application-platform \ 112 | -r $TAP_VERSION \ 113 | --format=json | jq '.[] | select(.name == "tanzu-framework-bundle-mac").id' ) 114 | 115 | pivnet download-product-files \ 116 | --download-dir $DOWNLOADS \ 117 | --product-slug='tanzu-application-platform' \ 118 | --release-version=$TAP_VERSION \ 119 | --product-file-id=$FILE_ID 120 | 121 | TANZU_DIR=$HOME/tanzu 122 | 123 | if [[ -d $TANZU_DIR ]] 124 | then 125 | UPGRADE_TANZU=true 126 | tanzu plugin delete imagepullsecret 2> /dev/null 127 | tanzu plugin delete package 2> /dev/null 128 | rm -rf $TANZU_DIR/cli/{package,secret,accelerator,services,apps} 129 | export TANZU_CLI_NO_INIT=true 130 | else 131 | UPGRADE_TANZU=false 132 | mkdir -p $TANZU_DIR 133 | fi 134 | 135 | tar xvf $DOWNLOADS/tanzu-framework-darwin-amd64.tar -C $TANZU_DIR 136 | MOST_RECENT_CLI=$(find $TANZU_DIR/cli/core/ -name tanzu-core-darwin_amd64 | xargs ls -t | head -n 1) 137 | sudo install -m 0755 $MOST_RECENT_CLI /usr/local/bin/tanzu 138 | 139 | tanzu config set features.global.context-aware-cli-for-plugins false 140 | 141 | if $UPGRADE_TANZU 142 | then 143 | tanzu update --yes --local $TANZU_DIR/cli 144 | tanzu plugin install secret --local $TANZU_DIR/cli 145 | tanzu plugin install package --local $TANZU_DIR/cli 146 | tanzu plugin install accelerator --local $TANZU_DIR/cli 147 | tanzu plugin install apps --local $TANZU_DIR/cli 148 | tanzu plugin install services --local $TANZU_DIR/cli 149 | else 150 | tanzu plugin install --local $TANZU_DIR/cli all 151 | fi 152 | 153 | tanzu version 154 | tanzu plugin list 155 | 156 | log "Done" 157 | -------------------------------------------------------------------------------- /install-prereqs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat <>> $line" 29 | done 30 | echo "" 31 | } 32 | 33 | function usingWsl() { 34 | uname -r | grep -qi 'microsoft' 35 | } 36 | 37 | if [[ "$(uname -s)/$(uname -m)" != "Linux/x86_64" ]] 38 | then 39 | log "Sorry, this script only handles Linux x86_64 systems" 40 | exit 1 41 | fi 42 | 43 | log "Installing basic tools" 44 | 45 | sudo apt-get update -y 46 | sudo apt-get install -y \ 47 | apt-transport-https \ 48 | ca-certificates \ 49 | curl \ 50 | gnupg \ 51 | lsb-release \ 52 | jq 53 | 54 | if usingWsl 55 | then 56 | log "It looks like you are running under WSL" \ 57 | "You must install Docker Desktop if you have not done so already" \ 58 | "This script will install the docker CLI only" 59 | 60 | sudo apt-get install -y docker 61 | 62 | else 63 | log "Removing any existing docker installation" 64 | 65 | sudo apt-get remove -y docker docker-engine docker.io containerd runc 66 | 67 | log "Installing new version of docker" 68 | 69 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 70 | echo \ 71 | "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ 72 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 73 | sudo apt-get update -y 74 | sudo apt-get install -y docker-ce docker-ce-cli containerd.io 75 | fi 76 | 77 | log "Adding $USER to docker group (logout/in to take effect)" 78 | sudo usermod -a -G docker $USER 79 | 80 | DOWNLOADS=/tmp/downloads 81 | mkdir -p $DOWNLOADS 82 | 83 | log "Installing kubectl" 84 | 85 | curl -Lo $DOWNLOADS/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" 86 | sudo install -o root -g root -m 0755 $DOWNLOADS/kubectl /usr/local/bin/kubectl 87 | 88 | log "Installing kind" 89 | 90 | curl -Lo $DOWNLOADS/kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 91 | sudo install -o root -g root -m 0755 $DOWNLOADS/kind /usr/local/bin/kind 92 | 93 | log "Installing carvel tools" 94 | 95 | sudo sh -c 'curl -L https://carvel.dev/install.sh | bash' 96 | 97 | log "Installing kn" 98 | 99 | curl -Lo $DOWNLOADS/kn https://github.com/knative/client/releases/latest/download/kn-linux-amd64 100 | sudo install -o root -g root -m 0755 $DOWNLOADS/kn /usr/local/bin/kn 101 | 102 | log "Installing kp" 103 | 104 | curl -Lo $DOWNLOADS/kp https://github.com/vmware-tanzu/kpack-cli/releases/download/v0.4.2/kp-linux-0.4.2 105 | sudo install -o root -g root -m 0755 $DOWNLOADS/kp /usr/local/bin/kp 106 | 107 | log "Installing pivnet CLI" 108 | 109 | curl -Lo $DOWNLOADS/pivnet https://github.com/pivotal-cf/pivnet-cli/releases/download/v3.0.1/pivnet-linux-amd64-3.0.1 110 | sudo install -o root -g root -m 0755 $DOWNLOADS/pivnet /usr/local/bin/pivnet 111 | 112 | log "Installing tanzu CLI" 113 | 114 | read -p 'Tanzu Network UAA Refresh Token: ' PIVNET_TOKEN 115 | pivnet login --api-token="$PIVNET_TOKEN" 116 | 117 | ESSENTIALS_VERSION=$(pivnet releases -p tanzu-cluster-essentials --format=json | \ 118 | jq -r 'sort_by(.updated_at)[-1].version') 119 | 120 | log "Latest Tanzu Cluster Essentials release found is $ESSENTIALS_VERSION" 121 | 122 | ESSENTIALS_FILE_NAME=tanzu-cluster-essentials-linux-amd64-$ESSENTIALS_VERSION.tgz 123 | ESSENTIALS_FILE_ID=$(pivnet product-files \ 124 | -p tanzu-cluster-essentials \ 125 | -r $ESSENTIALS_VERSION \ 126 | --format=json | jq '.[] | select(.name == "'$ESSENTIALS_FILE_NAME'").id' ) 127 | 128 | pivnet download-product-files \ 129 | --download-dir $DOWNLOADS \ 130 | --product-slug='tanzu-cluster-essentials' \ 131 | --release-version=$ESSENTIALS_VERSION \ 132 | --product-file-id=$ESSENTIALS_FILE_ID 133 | 134 | TAP_VERSION=$(pivnet releases -p tanzu-application-platform --format=json | \ 135 | jq -r 'sort_by(.updated_at)[-1].version') 136 | 137 | log "Latest TAP release found is $TAP_VERSION" 138 | 139 | TAP_FILE_ID=$(pivnet product-files \ 140 | -p tanzu-application-platform \ 141 | -r $TAP_VERSION \ 142 | --format=json | jq '.[] | select(.name == "tanzu-framework-bundle-linux").id' ) 143 | 144 | pivnet download-product-files \ 145 | --download-dir $DOWNLOADS \ 146 | --product-slug='tanzu-application-platform' \ 147 | --release-version=$TAP_VERSION \ 148 | --product-file-id=$TAP_FILE_ID 149 | 150 | TANZU_DIR=$HOME/tanzu 151 | 152 | if [[ -d $TANZU_DIR ]] 153 | then 154 | UPGRADE_TANZU=true 155 | tanzu plugin delete imagepullsecret 2> /dev/null 156 | tanzu plugin delete package 2> /dev/null 157 | rm -rf $TANZU_DIR/cli/{package,secret,accelerator,services,apps} 158 | export TANZU_CLI_NO_INIT=true 159 | else 160 | UPGRADE_TANZU=false 161 | mkdir -p $TANZU_DIR 162 | fi 163 | 164 | tar xvf $DOWNLOADS/tanzu-framework-linux-amd64.tar -C $TANZU_DIR 165 | MOST_RECENT_CLI=$(find $TANZU_DIR/cli/core/ -name tanzu-core-linux_amd64 | xargs ls -t | head -n 1) 166 | sudo install $MOST_RECENT_CLI /usr/local/bin/tanzu 167 | 168 | tanzu config set features.global.context-aware-cli-for-plugins false 169 | 170 | if $UPGRADE_TANZU 171 | then 172 | tanzu update --yes --local $TANZU_DIR/cli 173 | tanzu plugin install secret --local $TANZU_DIR/cli 174 | tanzu plugin install package --local $TANZU_DIR/cli 175 | tanzu plugin install accelerator --local $TANZU_DIR/cli 176 | tanzu plugin install apps --local $TANZU_DIR/cli 177 | tanzu plugin install services --local $TANZU_DIR/cli 178 | else 179 | tanzu plugin install --local $TANZU_DIR/cli all 180 | fi 181 | 182 | tanzu version 183 | tanzu plugin list 184 | 185 | log "Done" 186 | -------------------------------------------------------------------------------- /kind-with-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -o errexit 3 | 4 | hostIp() { 5 | # This works on both macOS and Linux 6 | ifconfig -a | awk '/^(en|wl)/,/(inet |status|TX error)/ { if ($1 == "inet") { print $2; exit; } }' 7 | } 8 | 9 | # Create registry container unless it already exists 10 | ROOT=$(cd $(dirname $0) && pwd) 11 | REG_NAME='kind-registry' 12 | REG_PORT='5000' 13 | REGISTRY="$(hostIp):$REG_PORT" 14 | running="$(docker inspect -f '{{.State.Running}}' "${REG_NAME}" 2>/dev/null || true)" 15 | if [ "${running}" != 'true' ]; then 16 | echo "Creating local registry at $REGISTRY: user = admin, password = admin" 17 | docker run \ 18 | --detach \ 19 | -v "$ROOT/auth:/auth" \ 20 | -e "REGISTRY_AUTH=htpasswd" \ 21 | -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ 22 | -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \ 23 | --name "$REG_NAME" \ 24 | --publish "${REG_PORT}":5000 \ 25 | registry:2 26 | fi 27 | 28 | # Configure insecure registry if config file not present 29 | # (This can only work on Linux) 30 | if test -d /etc/docker && test ! -f /etc/docker/daemon.json 31 | then 32 | echo "Creating /etc/docker/daemon.json with $REGISTRY added as insecure registry" 33 | sudo tee /etc/docker/daemon.json > /dev/null <>> Tanzu Network credentials 94 | 95 | EOT 96 | 97 | findOrPrompt TN_USERNAME "Tanzu Network Username" 98 | findOrPrompt TN_PASSWORD "Tanzu Network Password (will be echoed)" true 99 | 100 | cat <>> Container Registry 103 | 104 | The container registry should be something like 'myuser/tap' for DockerHub or 105 | 'harbor-repo.example.com/myuser/tap' for an internal registry. 106 | 107 | EOT 108 | findOrPrompt REGISTRY "Container Registry" 109 | findOrPrompt REG_USERNAME "Registry Username" 110 | findOrPrompt REG_PASSWORD "Registry Password (will be echoed)" true 111 | 112 | cat <>> Application domain 115 | 116 | The default value for the domain to be used to host applications 117 | is 'vcap.me'. If you use this value then the will result in a purely 118 | local TAP installation, as all 'vcap.me' names resolve to the 119 | localhost address. If you use anything other than 'vcap.me' then 120 | a load-balancer will be created and you will have to map lookups 121 | for the domain to the address of that load-balancer. 122 | 123 | Note that applications will be deployed in the 'apps' sub-domain of 124 | your supplied domain. For example, if you use the domain 'tap.example.com' 125 | then your applications will end up with DNS names such as 126 | 'my-awesome-app.default.apps.tap.example.com'. 127 | 128 | The TAP GUI and Educates components will be placed under a 'sys' 129 | sub-domain, for example, 'gui.sys.tap.example.com'. 130 | 131 | EOT 132 | 133 | findOrPromptWithDefault DOMAIN "Domain" "vcap.me" 134 | 135 | REG_HOST=${REGISTRY%%/*} 136 | REG_BASE=${REGISTRY#*.*/} 137 | if [[ $REG_HOST != *.* ]] 138 | then 139 | # Using DockerHub 140 | REG_HOST='index.docker.io' 141 | REG_BASE=${REGISTRY%%/*} 142 | REGISTRY="$REG_HOST/$REGISTRY" 143 | fi 144 | 145 | cat <>> Installation profile 148 | 149 | This should either be one of the following two built-in profiles: 150 | 151 | * light 152 | * full 153 | 154 | Or it can be a list of one or more of the following packages, separated 155 | by spaces (values in brackets indicate prerequisites which will 156 | also be installed automatically by the script): 157 | 158 | * accelerator [source-controller] 159 | * api-portal 160 | * appliveview [appliveview-conventions] 161 | * appliveview-conventions [appliveview] 162 | * buildservice 163 | * cartographer [source-controller] 164 | * cnrs 165 | * convention-controller 166 | * developer-conventions [convention-controller] 167 | * image-policy-webhook 168 | * grype [scanning] 169 | * learningcenter 170 | * learningcenter-workshops [learningcenter] 171 | * ootb-supply-chain-basic [ootb-templates] 172 | * ootb-supply-chain-testing [tekton, ootb-templates] 173 | * ootb-supply-chain-testing-scanning 174 | [tekton, scanning, ootb-templates] 175 | * ootb-templates [convention-controller, cartographer] 176 | * scanning [grype] 177 | * service-bindings [services-toolkit] 178 | * services-toolkit [service-bindings] 179 | * signing (alias for image-policy-webhook) 180 | * source-controller 181 | * spring-boot-conventions [convention-controller] 182 | * tap-gui [appliveview] 183 | * tbs (alias for buildservice) 184 | * tekton 185 | 186 | Note that the choice of supply chain (e.g. testing) will also cause 187 | the matching ootb-supply-chain-* package and its dependencies 188 | to be installed. 189 | EOT 190 | 191 | findOrPromptWithDefault INSTALL_PROFILE "Profile" "full" 192 | 193 | validateAndEnableInstallationOptions 194 | 195 | cat <>> GUI Catalog Info URL 198 | 199 | The TAP GUI needs information about the components and systems which 200 | it should display. This is done by providing a URL to a 'catalog-info.yaml' 201 | file. The default value provided is a publicly accessible blank catalog. 202 | 203 | EOT 204 | 205 | findOrPromptWithDefault GUI_CATALOG_URL \ 206 | "Catalog URL" \ 207 | "https://github.com/ndwinton/tap-gui-blank-catalog/blob/main/catalog-info.yaml" 208 | 209 | cat <>> Default supply chain 212 | 213 | This should be one of the following: basic, testing, scanning or none 214 | 215 | EOT 216 | 217 | findOrPromptWithDefault SUPPLY_CHAIN "Supply chain" "basic" 218 | 219 | if [[ "$SUPPLY_CHAIN" != "none" ]] 220 | then 221 | 222 | cat <>> Extra supply chain 225 | 226 | It is possible to install more than one supply chain at a time, as long 227 | as the labels used to select workloads are distinct enough. 228 | It is, therefore, possible to install the combinations of basic+testing 229 | or basic+scanning supply chains together. However, it is not 230 | possible to combine testing+scanning. 231 | 232 | Do you want to install an extra supply chain? 233 | 234 | This should be one of the following: basic, testing, scanning or none 235 | 236 | EOT 237 | findOrPromptWithDefault EXTRA_SUPPLY_CHAIN "Extra supply chain" "none" 238 | else 239 | EXTRA_SUPPLY_CHAIN="none" 240 | fi 241 | 242 | validateAndEnableSupplyChainComponent 243 | validateExtraSupplyChain 244 | 245 | cat <>> Packages to exclude (from full or light profiles) 248 | 249 | You can use the short package names shown above 250 | 251 | EOT 252 | 253 | findOrPromptWithDefault EXCLUDED_PACKAGES "Excluded packages" "none" 254 | 255 | enablePreRequisites 256 | 257 | findOrPromptWithDefault APPS_DOMAIN "Applications domain" "apps.${DOMAIN}" 258 | 259 | ### Set up (global, sigh ...) data used elsewhere 260 | 261 | if isLocal 262 | then 263 | CNR_PROVIDER="local" 264 | CNR_LOCAL_DNS="true" 265 | AA_SERVICE_TYPE='NodePort' 266 | ALV_SERVICE_TYPE='ClusterIP' 267 | STORE_SERVICE_TYPE='NodePort' 268 | CONTOUR_SERVICE_TYPE='NodePort' 269 | 270 | else 271 | CNR_PROVIDER="" 272 | CNR_LOCAL_DNS="false" 273 | AA_SERVICE_TYPE='LoadBalancer' 274 | ALV_SERVICE_TYPE='LoadBalancer' 275 | STORE_SERVICE_TYPE='LoadBalancer' 276 | CONTOUR_SERVICE_TYPE='LoadBalancer' 277 | findOrPromptWithDefault EDUCATES_DOMAIN "Learning Center domain" "learn.$DOMAIN" 278 | fi 279 | 280 | banner "The following packages will be installed:" ${!ENABLED[*]} 281 | 282 | # Explicitly set the default namespace before any other commands 283 | 284 | kubectl config set-context --current --namespace default 285 | 286 | if $DO_INIT 287 | then 288 | deployKappAndSecretgenControllers 289 | createTapNamespace 290 | createTapRegistrySecret 291 | loadPackageRepository 292 | fi 293 | 294 | tanzu package available list --namespace tap-install 295 | 296 | # If using the 'unbundled' profiles these will configure 297 | # and install the appropriate packages, otherwise they will 298 | # just generate the config files 299 | 300 | configureCertManager 301 | configureContour 302 | configureFluxCDSourceController 303 | configureCloudNativeRuntimes 304 | configureConventionsController 305 | configureSourceController 306 | configureAppAccelerator 307 | configureTanzuBuildService 308 | configureChoreographer 309 | configureOotbTemplates 310 | configureOotbSupplyChains 311 | configureDeveloperConventions 312 | configureSpringBootConventions 313 | configureAppLiveView 314 | configureTapGui 315 | configureLearningCenter 316 | configureScstStore 317 | configureSigning 318 | configureScanning 319 | configureApiPortal 320 | configureTekton 321 | configureServicesToolkit 322 | configureServiceBindings 323 | 324 | configureBuiltInProfiles 325 | 326 | configureExtraSupplyChain # Has to be done after profile install 327 | 328 | configureImageSigningPolicy 329 | 330 | banner "Setting up secrets, accounts and roles for default developer namespace" 331 | 332 | tanzu secret registry delete registry-credentials -y || true 333 | waitForRemoval kubectl get secret registry-credentials -o json 334 | 335 | # The following is a workaround for a Beta 2/3 bug 336 | if [[ "$REG_HOST" == "index.docker.io" ]] 337 | then 338 | REG_CRED_HOST="https://index.docker.io/v1/" 339 | else 340 | REG_CRED_HOST=$REG_HOST 341 | fi 342 | 343 | tanzu secret registry add registry-credentials \ 344 | --server "$REG_CRED_HOST" \ 345 | --username "$REG_USERNAME" \ 346 | --password "$REG_PASSWORD" \ 347 | --namespace default \ 348 | --export-to-all-namespaces -y || true 349 | 350 | cat > developer-namespace-setup.yaml <