Note: if an an import command has been re-run on an imported cluster, the above annotation for the cluster object can be used to force Rancher to redeploy the full agent manifest. The initial agent deployment from the import command does not contain the full spec that Rancher maintains after being imported.
Increase Rancher loglevel
LEVEL=info # change to debug, etc.
for rancherpod in `kubectl get pods -n cattle-system -l app=rancher --template '{{range.items}}{{.metadata.name}}{{"\n"}}{{end}}'`
do
echo $rancherpod
kubectl exec -n cattle-system $rancherpod -- loglevel --set $LEVEL
done
Or use our script to automate the temporary debug loglevel and capture the logs
kubectl get clusters.management.cattle.io -o custom-columns="ID:.metadata.name,NAME:.spec.displayName,DRIVER:.status.driver,K8S_VERSION:.status.version.gitVersion,CREATED:.metadata.creationTimestamp,DELETED:.metadata.deletionTimestamp,LAST_READY:.status.conditions[?(@.type == 'Ready')].lastUpdateTime,READY:.status.conditions[?(@.type == 'Ready')].status" --sort-by=.metadata.creationTimestamp
Nodes
kubectl get nodes.management.cattle.io -A -o custom-columns="NAMESPACE:.metadata.namespace,ID:.metadata.name,NAME:.status.nodeName,K8S:status.internalNodeStatus.nodeInfo.kubeletVersion,CP:spec.controlPlane,ETCD:spec.etcd,WORKER:spec.worker,OS:status.internalNodeStatus.nodeInfo.osImage,KERNEL:.status.internalNodeStatus.nodeInfo.kubeletVersion"
Machines with machine-id
kubectl get machine.cluster.x-k8s.io -n fleet-default -o custom-columns="CLUSTER:.metadata.labels.cluster\.x-k8s\.io/cluster-name,NAME:.metadata.name,CREATED:.metadata.creationTimestamp,MACHINE-ID:..metadata.labels.rke\.cattle\.i
o/machine-id"
Users
kubectl get users.management.cattle.io user-nvs7c -o custom-columns=ID:'{.metadata.name},Name:'{.username},DisplayName:'{.displayName}'
Tokens
kubectl get tokens.management.cattle.io -o custom-columns=Name:'{.metadata.name}',ID:'{.userId}',DisplayName:'{.userPrincipal.displayName}',User:'{.userPrincipal.loginName}',Created:'{.metadata.creationTimestamp}'
Kubernetes
Find leader leases
kubectl get leases -A
Find leader components (individual method) - for old k8s versions, may not work
#### kube-controller-manager
kubectl -n kube-system get endpoints kube-controller-manager -o jsonpath='{.metadata.annotations.control-plane\.alpha\.kubernetes\.io/leader}'
#### kube-scheduler
kubectl -n kube-system get endpoints kube-scheduler -o jsonpath='{.metadata.annotations.control-plane\.alpha\.kubernetes\.io/leader}'
#### rancher before 2.8.3
kubectl -n kube-system get configmap cattle-controllers -o jsonpath='{.metadata.annotations.control-plane\.alpha\.kubernetes\.io/leader}'
#### rancher after 2.8.3
kubectl -n kube-system get lease cattle-controllers -o json | jq -r '.spec.holderIdentity'
Test permission of a specific user
kubectl auth can-i get clusters/<clusterID> --as <userID>
kubectl hacks
Check API endpoints
kubectl get --raw='/readyz?verbose'
OR, from a control plane node
curl -k
https://localhost:6443/livez?verbose
List all resources in a namespace
kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n <namespace>
Count of all Kubernetes objects
for i in $(kubectl api-resources --verbs=list -o name | sort -n); do
echo -n "$i : "
kubectl get $i -A --no-headers 2>/dev/null | wc -l
done
List all running pods by restart count
kubectl get pods --sort-by="{.status.containerStatuses[:1].restartCount}" -A
List all pods by node
kubectl get pods -o wide --sort-by="{.spec.nodeName}" -A
Sort nodes by age
kubectl get nodes --sort-by=".status.conditions[?(@.reason == 'KubeletReady' )].lastTransitionTime"
List all not Running pods
kubectl get pods --field-selector="status.phase!=Succeeded,status.phase!=Running" -A
List all pods with PVC
kubectl get pods --all-namespaces -o=json | jq -c '.items[] | {name: .metadata.name, namespace: .metadata.namespace, claimName: .spec | select( has ("volumes") ).volumes[] | select( has ("persistentVolumeClaim") ).persistentVolumeClaim.claimName }'
List all namespaces with project IDs
kubectl get ns -A -o json | jq '.items[] | {name: .metadata.name, projectid: .metadata.labels."field.cattle.io/projectId"}'
With cluster:project ID format
kubectl get ns -A -o json | jq '.items[] | {name: .metadata.name, projectid: .metadata.annotations."field.cattle.io/projectId"}'
List all pods running on etcd or control plane
##### etcd
for n in $(kubectl get nodes -l node-role.kubernetes.io/etcd=true --no-headers | cut -d " " -f1)
do
kubectl get nodes --field-selector metadata.name=${n} --no-headers; kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=${n}; echo
done
# controlplane
for n in $(kubectl get nodes -l node-role.kubernetes.io/controlplane=true --no-headers | cut -d " " -f1)
do
kubectl get nodes --field-selector metadata.name=${n} --no-headers; kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=${n}; echo
done
List all namespaces by cluster-id:project-id
kubectl get ns -A -o json | jq '.items[] | {name: .metadata.name, projectid: .metadata.annotations."field.cattle.io/projectId"}'
List all namespaces by just project-id
kubectl get ns -A -o json | jq '.items[] | {name: .metadata.name, projectid: .metadata.labels."field.cattle.io/projectId"}'
Delete all pods with a certain status
Eg, Failed status in the current namespace:
kubectl delete pod --field-selector="status.phase==Failed"
Force delete all pods not in a Running state (warning: potentially harmful):
kubectl -A --no-headers get pods | awk '{if ($4 != "Running") system ("kubectl -n " $1 " delete pod " $2 " --grace-period=0 " " --force ")}'
Decode a secret oneliner
The below decodes a secret with multiple keys within data, in this case only decode the alertmanager.yaml key
WARNING: This is fairly desctructive, intended for worst case scenarios where the tokens got invalidated, such as when the CA got recreated. Credit to this gist.
kubectl get secret -A | awk '{ if ($3 == "kubernetes.io/service-account-token") system("kubectl -n " $1 " delete secret " $2) }'
kubectl get po -A | awk '{ if ($4 =="CrashLoopBackOff") system("kubectl delete po --force --grace-period=0 -n " $1 " " $2) }'
kubectl get po -A | awk '{ if ($4 =="Terminating") system("kubectl delete po --force --grace-period=0 -n " $1 " " $2) }'
kubectl get po -A | awk '{ if ($4 =="Error") system("kubectl delete po --force --grace-period=0 -n " $1 " " $2) }'
##### Optional - all pods
kubectl delete pods -A --all --force --grace-period=0
Collect pprof profiling data from kube-apiserver
In RKEv1 profiling is not enabled on the kube-apiserver by defaults, edit the cluster as YAML to add:
services:
kube-api:
extra_args:
profiling: 'true'
With the above in place, once there is a control plane node experiencing the issue, SSH in and use the following steps (while the issue is occurring).
(Optional), if the kubectl binary is not installed, copy it from the kubelet container: docker cp kubelet:/usr/local/bin/kubectl .
Start a kubectl proxy session in the background (assumes the above steps were used exactly, modify slightly if needed): ./kubectl --kubeconfig kubeconfig_admin.yaml proxy &
Obtain profiling data with the below loop:
for i in allocs block goroutine heap mutex threadcreate trace
do
echo $i
curl -s http://127.0.0.1:8001/debug/pprof/$i -o $i
done
##### Get a list of CoreDNS endpoints
kubectl get endpoints -n kube-system kube-dns -o=jsonpath='{.subsets[*].addresses[*].ip}'
##### Use the IP list above to add to the below loop
for coredns in <space separated list here>
do
echo "-- resolving against $coredns"
dig +short kubernetes.default.svc.cluster.local. @$coredns >& /dev/null
done
Port testing
These are useful if commands are limited, especially /dev/tcp which should be possible without any nc or curl etc.
Curl Rancher and check connectivity.
To the FQDN: curl -v -k https://rancher-sandbox.com/ping
Locally from Rancher node:
From inside Rancher container:
Output like that included below implies a break in connection between the source and destination on the return route from destination to source. A successful curl of Rancher's 'ping' will return a payload of pong after the handshakes.
curl -v -k https://rancher-sandbox.com/ping
* Trying 10.196.205.7:443...
* Connected to rancher-sandbox.pwc.com (10.196.205.7) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to rancher-sandbox.pwc.com:443
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to rancher-sandbox.pwc.com:443
Pass an SNI compliant request direct to an IP, useful to sending traffic to a node directly instead of behind a load balancer
##### Connect using a different port on the node (NodePort for example), this is useful for Istio where a Gateway might be configured to listen on the port that the load balancer is listening (443)
curl --connect-to example.com:443:<ip address>:31390 https://example.com/
##### Set the host header as needed while connecting to an IP, when no port changes are needed
curl --resolve www.example.com:443:192.0.2.1 https://www.example.com/
Perform requests with a proxy protocol header (--haproxy-procotol)
#### nsenter
ID=<contaier ID or name>
PID=$(docker inspect --format '{{ .State.Pid }}' $ID)
nsenter -a -t $PID <command>
#### Sidecar
docker run -it --net=container:$ID --pid=container:$ID --volumes-from=$ID leodotcloud/swiss-army-knife sh
Capture the Docker socket with socat
#### backup the socket
sudo mv /var/run/docker.sock /var/run/docker.sock.original
#### use tcp port 8089 proxy the original socket
sudo socat TCP-LISTEN:8089,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock.original
#### use the new socket to proxy the 8089 port
sudo socat UNIX-LISTEN:/var/run/docker.sock,fork TCP-CONNECT:127.0.0.1:8089
sudo tcpdump -i lo -netvv port 8089
Tcpdump to grab only headers
#### On port 80
sudo tcpdump -A -s 10240 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' | egrep --line-buffered "^........(GET |HTTP\/|POST |HEAD )|^[A-Za-z0-9-]+: " | sed -r 's/^........(GET |HTTP\/|POST |HEAD )/\n\1/g'
#### With nsenter, all ports:
nsenter -n -t $PID tcpdump -A -s 10240 '(((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' | egrep --line-buffered "^........(GET |HTTP\/|POST |HEAD )|^[A-Za-z0-9-]+: " | sed -r 's/^........(GET |HTTP\/|POST |HEAD )/\n\1/g'
Calico - Ip-over-IP - Tcpdump to trace Pod to Pod packet flow
wal_fsync_duration_seconds < 10ms = GOOD - preferrably well below
backend_commit_duration_seconds < 25ms = GOOD
wal_fsync_duration_seconds is latency etcd persistenting log entries to the disk, before applying it. After every write call, it's doing an fsync call to confirm data is written to disk - not in kernel memory etc.
backend_commit_duration_seconds etcd commits an incremental snapshot of it's most recent snapshot to disk.
Set a kubeconfig file for the cluster, if needed use the kubeconfig on an rke2-server node
export KUBECONFIG=/etc/rancher/rke2/rke2.yaml
Commands:
etcdctl check perf
for etcdpod in $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name); do kubectl -n kube-system exec $etcdpod -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl check perf"; done
etcdctl endpoint status
for etcdpod in $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name); do kubectl -n kube-system exec $etcdpod -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl endpoint status"; done
etcdctl endpoint health
for etcdpod in $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name); do kubectl -n kube-system exec $etcdpod -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl endpoint health"; done
etcdctl alarm list
for etcdpod in $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name); do kubectl -n kube-system exec $etcdpod -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl alarm list"; done
etcdctl compact
rev=$(kubectl -n kube-system exec $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name | head -1) -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl endpoint status --write-out fields | grep Revision | cut -d: -f2")
kubectl -n kube-system exec $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name | head -1) -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl compact \"$(echo $rev)\""
etcdctl defrag
kubectl -n kube-system exec $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name | head -1) -- sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl defrag --cluster"
etcd raw metrics
The below retrieves the metrics from the first etcd pod listed by kubectl in the cluster
kubectl -n kube-system exec $(kubectl -n kube-system get pod -l component=etcd --no-headers -o custom-columns=NAME:.metadata.name | head -1) -- sh -c "curl -L --cacert /var/lib/rancher/rke2/server/tls/etcd/server-ca.crt --cert /var/lib/rancher/rke2/server/tls/etcd/server-client.crt --key /var/lib/rancher/rke2/server/tls/etcd/server-client.key -s https://127.0.0.1:2379/metrics"
wal_fsync_duration_seconds < 10ms = GOOD - preferrably well below
backend_commit_duration_seconds < 25ms = GOOD
wal_fsync_duration_seconds is latency etcd persistenting log entries to the disk, before applying it. After every write call, it's doing an fsync call to confirm data is written to disk - not in kernel memory etc.
backend_commit_duration_seconds etcd commits an incremental snapshot of it's most recent snapshot to disk.
##### Pre-work
export CRI_CONFIG_FILE=/var/lib/rancher/rke2/agent/etc/crictl.yaml
etcdcontainer=$(/var/lib/rancher/rke2/bin/crictl ps --label io.kubernetes.container.name=etcd --quiet)
##### Count objects
/var/lib/rancher/rke2/bin/crictl exec $etcdcontainer sh -c "ETCDCTL_ENDPOINTS='https://127.0.0.1:2379' ETCDCTL_CACERT='/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt' ETCDCTL_CERT='/var/lib/rancher/rke2/server/tls/etcd/server-client.crt' ETCDCTL_KEY='/var/lib/rancher/rke2/server/tls/etcd/server-client.key' ETCDCTL_API=3 etcdctl get /registry --prefix=true --keys-only" | grep -v ^$ | awk -F'/' '{ if ($3 ~ /cattle.io/) {h[$3"/"$4]++} else { h[$3]++ }} END { for(k in h) print h[k], k }' | sort -n > etcd-count-objecttype.txt
Object count (postgres - K3S)
SELECT * FROM ( SELECT count( 1 ) num, NAME FROM kine GROUP BY kine.name ) ab ORDER BY num DESC;
Object sizes (can take time...)
Note: this method counts the object sizes with: total size = current size * count #. This is not strictly accurate, but a decent indicator of size. Revisions can deviate in size over time (like adding/removing data in a ConfigMap). Counting every revision individually is probably not desired on large or production clusters, so this method of counting the total size based on the current object size is used. More info here if collecting each revision is needed, this may be best run on a snapshot restore to a temporary cluster
Prework
RKE1
Exec into the etcd container to use the etcdctl commands below to gather object sizes
docker exec -it etcd sh
RKE2
Download etcdctl to an etcd node in the cluster
Note: replace ETCD_VER as needed to closely match the version in use on the cluster
ETCD_VER=v3.5.21
DOWNLOAD_URL=https://storage.googleapis.com/etcd
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /usr/local/bin --strip-components=1 --no-same-owner
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
/usr/local/bin/etcdctl version
Export the necessary environment vars for use in the etcdctl commands below
DELETE FROM kine AS kv
USING (
SELECT kp.prev_revision AS id
FROM kine AS kp
WHERE
kp.name != 'compact_rev_key' AND
kp.prev_revision != 0 AND
kp.id <= $1
UNION
SELECT kd.id AS id
FROM kine AS kd
WHERE
kd.deleted != 0 AND
kd.id <= $2
) AS ks
WHERE kv.id = ks.id
Replace $1 and 2 with the ID that compaction should be limited to, usually the last record ID in the DB minus 2k-5k for safety.
To get the last record, something like this should work, please check: SELECT * FROM kine ORDER BY CREATED_TIME DESC LIMIT 1
Grab all high kube-apiserver/etcd request times
These examples use >=1s (1000ms) as the filter, adjust the regex [1-9][0-9]{3,}.+ms to a higher number, for eg [2-9][0-9]{3,}.+ms for >=2s.
Or, for higher than 10s add another digit: [1-9][0-9]{4,}.+ms
kube-apiserver
grep -hE '(total time:.[1-9][0-9]{3,}.+ms)' <log directory>/k8s/containerlogs/kube-apiserver
##### Or while tailing the container logs
docker logs -f --tail=1000 kube-apiserver |& grep -E '(total time:.[1-9][0-9]{3,}.+ms)'
grep -hE 'took too long (.[1-9][0-9]{3,}.+ms)' <log directory>/k8s/containerlogs/etcd
##### Or while tailing the container logs
docker logs -f --tail=1000 etcd |& grep -E 'took too long (.[1-9][0-9]{3,}.+ms)'
Test connectivity to all etcd members (RKE1)
for endpoint in $(docker exec etcd /bin/sh -c "etcdctl member list | cut -d, -f5"); do
echo "Validating connection to ${endpoint}/health"
docker run --net=host -v $(docker inspect kubelet --format '{{ range .Mounts }}{{ if eq .Destination "/etc/kubernetes" }}{{ .Source }}{{ end }}{{ end }}')/ssl:/etc/kubernetes/ssl:ro appropriate/curl -s -w "\n" --cacert $(docker exec etcd printenv ETCDCTL_CACERT) --cert $(docker exec etcd printenv ETCDCTL_CERT) --key $(docker exec etcd printenv ETCDCTL_KEY) "${endpoint}/health"
done
for endpoint in $(docker exec etcd /bin/sh -c "etcdctl member list | cut -d, -f4"); do
echo "Validating connection to ${endpoint}/version";
docker run --net=host -v $(docker inspect kubelet --format '{{ range .Mounts }}{{ if eq .Destination "/etc/kubernetes" }}{{ .Source }}{{ end }}{{ end }}')/ssl:/etc/kubernetes/ssl:ro appropriate/curl --http1.1 -s -w "\n" --cacert $(docker exec etcd printenv ETCDCTL_CACERT) --cert $(docker exec etcd printenv ETCDCTL_CERT) --key $(docker exec etcd printenv ETCDCTL_KEY) "${endpoint}/version"
done
See example below, run against the local Rancher cluster where "fleet-local" is the name of the workspace and "appcd-local-local-stuff" is the specific bundle to return the status. An alternative to the status in the UI.
kubectl get bundle -n fleet-local appcd-local-local-stuff -o jsonpath='{.status.summary}'
{"desiredReady":1,"ready":1}
Tools
Working with device streams
Container logs often contain both stdout/stderr, this can be annoying to pipe or redirect.
The |& and &> are a convenient short hand for this:
docker logs kubelet --tail=5000 |& less
docker logs kubelet --tail=5000 &> kubelet.log
Bonus tip:
docker logs kubelet |& less -Ip CrashLoop
Starts less at the first occurrence of a pattern (-p), ignoring case (-I).
Issues involving multiple components or HA systems spread across many nodes (like the CNI) one can gather logs from ALL nodes, then open ALL logs for related components in one session of lnav.
This will put everything into one indexed view that you can easily navigate in time order. You can start filtering logs out lines or types of entries (matched by regex) as you determine them to be unrelated or benign, and then view histograms and compare to timelines of events to determine what entries may be related to the issue you are investigating.
lnav can handle multiple files/directories at once and will unzip files as needed, for eg lnav messages*
Shell function to simplify the download of logs from a ticket folder in the SCC S3 bucket
function scc-logs {
##### Note, this assumes saml2aws is configured to manage a profile called "scc"
# See the steps for "Access via CLI" in: https://confluence.suse.com/display/SSTE/File+uploads+to+SUSE+Support
BASE_DIR="${HOME}/Downloads"
WORKING_DIR="$BASE_DIR/$1"
if [ -z "$1" ]
then
echo "No argument supplied"
return 1
fi
if [ ! -d "$WORKING_DIR" ]
then
mkdir -p "$WORKING_DIR"
cd "$WORKING_DIR"
scc-login
aws --region eu-central-1 --profile scc s3 sync s3://suse-customer-uploads/$1/ $WORKING_DIR/
else
echo "Dir already exists, switching to it"
cd "$WORKING_DIR"
if read -q "REPLY?Do you want to sync files from s3 again? (y/n) "
then
echo; scc-login
aws --region eu-central-1 --profile scc s3 sync s3://suse-customer-uploads/$1/ $WORKING_DIR/
fi
fi
}
function scc-login {
echo "Checking for credentials"
if ! aws --profile scc sts get-caller-identity >> /dev/null
then
echo "Credentials expired, logging in"
saml2aws login
fi
}
ag / ack
A good alternative to grep -r, fast recursive string matching.