<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>pmcgrath</title>
    <description>Various tech tidbits that I want to record.
</description>
    <link>https://pmcgrath.github.io/</link>
    <atom:link href="https://pmcgrath.github.io/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Thu, 27 Sep 2018 09:56:35 +0000</pubDate>
    <lastBuildDate>Thu, 27 Sep 2018 09:56:35 +0000</lastBuildDate>
    <generator>Jekyll v3.7.4</generator>
    
      <item>
        <title>Using pod security policies with kubeadm</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;p&gt;Illustrate using &lt;a href=&quot;https://kubernetes.io/docs/concepts/policy/pod-security-policy/&quot;&gt;pod security policies&lt;/a&gt; with a &lt;a href=&quot;https://github.com/kubernetes/kubeadm&quot;&gt;kubeadm&lt;/a&gt; installation of kubernetes&lt;/p&gt;

&lt;p&gt;Pod security policies are a mechanism to restrict what a container can do when run on kubernetes such as preventing running as privileged containers, running with host networking etc.&lt;/p&gt;

&lt;p&gt;Read the &lt;a href=&quot;https://pmcgrath.net/using-pod-security-policies-with-kubeadm&quot;&gt;docs&lt;/a&gt; to see how this can be used to improve security&lt;/p&gt;

&lt;p&gt;I struggled to find any information on bootstrapping a kubeadm cluster with the same, hence this content&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;/h2&gt;
&lt;p&gt;This post is very long so I can do a full illustration, in short you need to&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;On master run kubeadm init with the PodSecurityPolicy admission controller enabled&lt;/li&gt;
  &lt;li&gt;Add some pod security policies with RBAC config - enough to allow CNI and DNS etc. to start
    &lt;ul&gt;
      &lt;li&gt;CNI daemonsets will not start without this&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Apply your CNI provider which can use one of the previously created pod security policies&lt;/li&gt;
  &lt;li&gt;Complete configuring the cluster adding nodes via kubeadm join&lt;/li&gt;
  &lt;li&gt;As you add more workloads to the cluster check if you need additional pod security policies and RBAC configuration for the same&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-we-will-do&quot;&gt;What we will do&lt;/h2&gt;
&lt;p&gt;This is the list of steps I took to get pod security policies running on a kubeadm installation&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Configure the pod security policy admission &lt;a href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#podsecuritypolicy&quot;&gt;controller&lt;/a&gt; for master init&lt;/li&gt;
  &lt;li&gt;Configure some pod security policies for the control plane components&lt;/li&gt;
  &lt;li&gt;Configure a CNI provider - Will use flannel here&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Will then use the following to demo some other pod security policy scenarios&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Install an nginx-ingress controller which has some specfic requirements - This is just to illustrate adding additional policies&lt;/li&gt;
  &lt;li&gt;Install a regular service that has no specific pod security policy requirements - Based on &lt;a href=&quot;https://hub.docker.com/r/kennethreitz/httpbin/&quot;&gt;httpbin.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;environment&quot;&gt;Environment&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Will just illustrate on a single node rather than a multi-node cluster with HA&lt;/li&gt;
  &lt;li&gt;Ubuntu
    &lt;ul&gt;
      &lt;li&gt;Swap off as required by kubeadm&lt;/li&gt;
      &lt;li&gt;Timezone configured for UTC&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Docker
    &lt;ul&gt;
      &lt;li&gt;Assumes current user is in the docker group&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;kubernetes 1.11.3 - with RBAC&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;prepare-master&quot;&gt;Prepare master&lt;/h2&gt;
&lt;p&gt;Follow the instructions to install &lt;a href=&quot;https://kubernetes.io/docs/setup/independent/install-kubeadm/&quot;&gt;kubeadm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets install &lt;a href=&quot;https://stedolan.github.io/jq/manual/&quot;&gt;jq&lt;/a&gt; which we will use for some json output processing&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y jq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Verify kubeadm version&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo kubeadm version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a directory somewhere for the content we will create below, all below instructions assume you are in this directory&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir ~/psp-inv
cd ~/psp-inv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;kubeadm-config-file&quot;&gt;kubeadm config file&lt;/h2&gt;
&lt;p&gt;Will create this file and use it for &lt;strong&gt;kubeadm init&lt;/strong&gt; on the master&lt;/p&gt;

&lt;p&gt;Create a &lt;strong&gt;kubeadm-config.yaml&lt;/strong&gt; file with this content - note we have to specify the podSubnet of 10.244.0.0/16 for flannel&lt;/p&gt;

&lt;p&gt;Note this file is minimal for this demo and if you use a later version of kubeadm you may need to alter the apiVersion&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
apiServerExtraArgs:
  enable-admission-plugins: PodSecurityPolicy
controllerManagerExtraArgs:
  address: 0.0.0.0
kubernetesVersion: v1.11.3
networking:
  podSubnet: 10.244.0.0/16
schedulerExtraArgs:
  address: 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;master-init&quot;&gt;Master init&lt;/h2&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo kubeadm init --config kubeadm-config.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Follow the instructions from the above command output to get your own copy of the kubeconfig file&lt;/p&gt;

&lt;p&gt;If you want to add worker nodes to the cluster, note the join message&lt;/p&gt;

&lt;p&gt;Lets check the master node status with&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get nodes

NAME                    STATUS     ROLES     AGE       VERSION
pmcgrath-k8s-master     NotReady   master    1m        v1.11.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the node is not ready as it is waiting for CNI&lt;/p&gt;

&lt;p&gt;Lets check the pods&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get pods --all-namespaces
No resources found.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So none appear to be running, would normally see pods with some pending if we had not enabled the pod security policy admission control&lt;/p&gt;

&lt;p&gt;Lets check docker&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker container ls --format '{{ .Names }}'

k8s_kube-scheduler_kube-scheduler-pmcgrath-k8s-master_kube-system_a00c35e56ebd0bdfcd77d53674a5d2a1_0
k8s_kube-controller-manager_kube-controller-manager-pmcgrath-k8s-master_kube-system_fd832ada507cef85e01885d1e1980c37_0
k8s_etcd_etcd-pmcgrath-k8s-master_kube-system_16a8af6b4a79e9b0f81092f85eab37cf_0
k8s_kube-apiserver_kube-apiserver-pmcgrath-k8s-master_kube-system_db201a8ecaf8e99623b425502a6ba627_0
k8s_POD_kube-controller-manager-pmcgrath-k8s-master_kube-system_fd832ada507cef85e01885d1e1980c37_0
k8s_POD_kube-scheduler-pmcgrath-k8s-master_kube-system_a00c35e56ebd0bdfcd77d53674a5d2a1_0
k8s_POD_kube-apiserver-pmcgrath-k8s-master_kube-system_db201a8ecaf8e99623b425502a6ba627_0
k8s_POD_etcd-pmcgrath-k8s-master_kube-system_16a8af6b4a79e9b0f81092f85eab37cf_0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So containers are running, but not showing up with kubectl&lt;/p&gt;

&lt;p&gt;Lets check events&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get events --namespace kube-system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;will see something like  Error creating: pods “kube-proxy-“ is forbidden: no providers available to validate pod request&lt;/p&gt;

&lt;h2 id=&quot;configure-pod-security-policies&quot;&gt;Configure pod security policies&lt;/h2&gt;
&lt;p&gt;I have went with configuring&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A default pod security policy that any workload can use, has no privileges and should be good for most workloads
    &lt;ul&gt;
      &lt;li&gt;Will create an RBAC ClusterRole&lt;/li&gt;
      &lt;li&gt;Will create an RBAC ClusterRoleBinding for any authenticated users&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A privileged pod security policy that I grant nodes and all service accounts in the kube-system namespace access to
    &lt;ul&gt;
      &lt;li&gt;Thinking is access to this namespace is restricted&lt;/li&gt;
      &lt;li&gt;Should only run k8s components in this namespace&lt;/li&gt;
      &lt;li&gt;Will create an RBAC ClusterRole&lt;/li&gt;
      &lt;li&gt;Will create an RBAC RoleBinding in the kube-system namespace&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a &lt;strong&gt;default-psp-with-rbac.yaml&lt;/strong&gt; file with this content&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  annotations:
    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
    apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
    seccomp.security.alpha.kubernetes.io/defaultProfileName:  'docker/default'
  name: default
spec:
  allowedCapabilities: []  # default set of capabilities are implicitly allowed
  allowPrivilegeEscalation: false
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      # Forbid adding the root group.
      - min: 1
        max: 65535
  hostIPC: false
  hostNetwork: false
  hostPID: false
  privileged: false
  readOnlyRootFilesystem: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsNonRoot'
  supplementalGroups:
    rule: 'RunAsNonRoot'
    ranges:
      # Forbid adding the root group.
      - min: 1
        max: 65535
  volumes:
  - 'configMap'
  - 'downwardAPI'
  - 'emptyDir'
  - 'persistentVolumeClaim'
  - 'projected'
  - 'secret'
  hostNetwork: false
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

---

# Cluster role which grants access to the default pod security policy
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: default-psp
rules:
- apiGroups:
  - policy
  resourceNames:
  - default
  resources:
  - podsecuritypolicies
  verbs:
  - use

---

# Cluster role binding for default pod security policy granting all authenticated users access
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: default-psp
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: default-psp
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:authenticated
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;strong&gt;privileged-psp-with-rbac.yaml&lt;/strong&gt; file with this content&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Should grant access to very few pods, i.e. kube-system system pods and possibly CNI pods
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  annotations:
    # See https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
  name: privileged
spec:
  allowedCapabilities:
  - '*'
  allowPrivilegeEscalation: true
  fsGroup:
    rule: 'RunAsAny'
  hostIPC: true
  hostNetwork: true
  hostPID: true
  hostPorts:
  - min: 0
    max: 65535
  privileged: true
  readOnlyRootFilesystem: false
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  volumes:
  - '*'

---

# Cluster role which grants access to the privileged pod security policy
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: privileged-psp
rules:
- apiGroups:
  - policy
  resourceNames:
  - privileged
  resources:
  - podsecuritypolicies
  verbs:
  - use

---

# Role binding for kube-system - allow nodes and kube-system service accounts - should take care of CNI i.e. flannel running in the kube-system namespace
# Assumes access to the kube-system is restricted
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kube-system-psp
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: privileged-psp
subjects:
# For the kubeadm kube-system nodes
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:nodes
# For all service accounts in the kube-system namespace
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:serviceaccounts:kube-system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;apply-the-above-pod-security-policies-with-rbac-configuration&quot;&gt;Apply the above pod security policies with RBAC configuration&lt;/h3&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply -f default-psp-with-rbac.yaml
kubectl apply -f privileged-psp-with-rbac.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;check&quot;&gt;Check&lt;/h3&gt;
&lt;p&gt;Control plane pods will turn up in a running state after some time, coredns pods will be pending - waiting on CNI&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get pods --all-namespaces --output wide --watch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Control plane pods will start failing again until CNI is configured, as the node is still not ready&lt;/p&gt;

&lt;h3 id=&quot;install-flannel&quot;&gt;Install flannel&lt;/h3&gt;
&lt;p&gt;See &lt;a href=&quot;https://github.com/coreos/flannel&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Will only be able to complete this as the &lt;strong&gt;privileged&lt;/strong&gt; pod security policy will now exist and the flannel service account in the kube-system will be able to use&lt;/p&gt;

&lt;p&gt;If using a different CNI provider you should use their installation instructions, will probably need to alter the podSubnet in the kubeadm-config.yaml file used for kubeadm init&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;check-1&quot;&gt;Check&lt;/h3&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get pods --all-namespaces --output wide --watch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All pods will eventually get to a running status including coredns pod(s)&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Node is now ready&lt;/p&gt;

&lt;h3 id=&quot;allow-workloads-on-the-master&quot;&gt;Allow workloads on the master&lt;/h3&gt;
&lt;p&gt;If you want to spin up worker nodes, you can do so as normal using the &lt;strong&gt;kubeadm join&lt;/strong&gt; command using the output from kubeadm init, skipping this here&lt;/p&gt;

&lt;p&gt;Nothing special needed on worker nodes joining the cluster pod security policy wise&lt;/p&gt;

&lt;p&gt;To allow workloads on the master node, as we are just trying to verify on a single node cluster&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl taint nodes --all node-role.kubernetes.io/master-
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;nginx-ingress&quot;&gt;nginx ingress&lt;/h2&gt;
&lt;p&gt;Will use the manifest from &lt;a href=&quot;https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will create a new namespace and a single instance ingress controller, which is enough to illustrate additional pod security policies&lt;/p&gt;

&lt;h3 id=&quot;namespace&quot;&gt;Namespace&lt;/h3&gt;
&lt;p&gt;Since the namespace will not yet exist, lets create so we can reference service accounts and create a role binding&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl create namespace ingress-nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;lets-create-a-pod-security-policy&quot;&gt;Lets create a pod security policy&lt;/h3&gt;
&lt;p&gt;This pod security policy is based on the deployment &lt;a href=&quot;https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml&quot;&gt;manifest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a file &lt;strong&gt;nginx-ingress-psp-with-rbac.yaml&lt;/strong&gt; with this content&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  annotations:
    # Assumes apparmor available
    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
    apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
    seccomp.security.alpha.kubernetes.io/defaultProfileName:  'docker/default'
  name: ingress-nginx
spec:
  # See nginx-ingress-controller deployment at https://github.com/kubernetes/ingress-nginx/blob/master/deploy/mandatory.yaml
  # See also https://github.com/kubernetes-incubator/kubespray/blob/master/roles/kubernetes-apps/ingress_controller/ingress_nginx/templates/psp-ingress-nginx.yml.j2
  allowedCapabilities:
  - NET_BIND_SERVICE
  allowPrivilegeEscalation: true
  fsGroup:
    rule: 'MustRunAs'
    ranges:
    - min: 1
      max: 65535
  hostIPC: false
  hostNetwork: false
  hostPID: false
  hostPorts:
  - min: 80
    max: 65535
  privileged: false
  readOnlyRootFilesystem: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
    ranges:
    - min: 33
      max: 65535
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
    # Forbid adding the root group.
    - min: 1
      max: 65535
  volumes:
  - 'configMap'
  - 'downwardAPI'
  - 'emptyDir'
  - 'projected'
  - 'secret'

---

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ingress-nginx-psp
  namespace: ingress-nginx
rules:
- apiGroups:
  - policy
  resourceNames:
  - ingress-nginx
  resources:
  - podsecuritypolicies
  verbs:
  - use

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ingress-nginx-psp
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx-psp
subjects:
# Lets cover default and nginx-ingress-serviceaccount service accounts
# Could have altered default-http-backend deployment to use the same service acccount to avoid granting the default service account access
- kind: ServiceAccount
  name: default
- kind: ServiceAccount
  name: nginx-ingress-serviceaccount
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lets apply&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply -f nginx-ingress-psp-with-rbac.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;create-nginx-ingress-workload&quot;&gt;Create nginx-ingress workload&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Will remove the controller –publish-service arg as we do not need here&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -s https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml | sed '/--publish-service/d'  | kubectl apply -f -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check for pods&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get pods --namespace ingress-nginx --watch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Can now see the pod security policy is attached with an annotation with&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get pods --namespace ingress-nginx --selector app.kubernetes.io/name=ingress-nginx -o json | jq -r  '.items[0].metadata.annotations.&quot;kubernetes.io/psp&quot;'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;httpbinorg-workload&quot;&gt;Httpbin.org workload&lt;/h2&gt;
&lt;p&gt;Lets deploy a workload where the default pod security policy will suffice&lt;/p&gt;

&lt;p&gt;Create a &lt;strong&gt;httpbin.yaml&lt;/strong&gt; file with this content&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: httpbin
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: httpbin
  template:
    metadata:
      labels:
        app.kubernetes.io/name: httpbin
    spec:
      containers:
      - args: [&quot;-b&quot;, &quot;0.0.0.0:8080&quot;, &quot;httpbin:app&quot;]
        command: [&quot;gunicorn&quot;]
        image: docker.io/kennethreitz/httpbin:latest
        imagePullPolicy: Always
        name: httpbin
        ports:
        - containerPort: 8080
          name: http
      restartPolicy: Always

---

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: &quot;nginx&quot;
  labels:
    app.kubernetes.io/name: httpbin
  name: httpbin
spec:
  rules:
  - host: my.httpbin.com
    http:
      paths:
      - path:
        backend:
          serviceName: httpbin
          servicePort: 8080

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: httpbin
  name: httpbin
spec:
  ports:
  - name: http
    port: 8080
  selector:
    app.kubernetes.io/name: httpbin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create namespace and run in workload&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl create namespace demo
kubectl apply --namespace demo -f httpbin.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lets check that the pod exists and the default policy was used&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get pods --namespace demo

kubectl get pods --namespace demo --selector app.kubernetes.io/name=httpbin -o json | jq -r  '.items[0].metadata.annotations.&quot;kubernetes.io/psp&quot;'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;test-workload&quot;&gt;Test workload&lt;/h3&gt;
&lt;p&gt;Will do so by calling via ingress controller pod instance - I have no ingress service for this demo&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Get nginx ingress controller pod IP
nginx_ip=$(kubectl get pods --namespace ingress-nginx --selector app.kubernetes.io/name=ingress-nginx --output json | jq -r .items[0].status.podIP)

# Test ingress and out httpbin workload
curl -H 'Host: my.httpbin.com' http://$nginx_ip/get
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;resets&quot;&gt;Resets&lt;/h2&gt;
&lt;p&gt;If like me you mess this up regularly, you can reset and restart with&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Note: Will loose PKI also which is fine here as kubeadm master init will re-create
sudo kubeadm reset

# Should flush iptable rules after a kubeadm reset, see https://blog.heptio.com/properly-resetting-your-kubeadm-bootstrapped-cluster-nodes-heptioprotip-473bd0b824aa
sudo iptables -F &amp;amp;&amp;amp; sudo iptables -t nat -F &amp;amp;&amp;amp; sudo iptables -t mangle -F &amp;amp;&amp;amp; sudo iptables -X
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/policy/pod-security-policy&quot;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/issues/62566#issuecomment-381360838&quot;&gt;Github issues comment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/freach/kubernetes-security-best-practice/tree/master/PSP&quot;&gt;Security recommendations&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/tree/master/cluster/gce/addons/podsecuritypolicies&quot;&gt;GCE policies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 13 Sep 2018 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/using-pod-security-policies-with-kubeadm</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/using-pod-security-policies-with-kubeadm</guid>
        
        
        <category>k8s</category>
        
      </item>
    
      <item>
        <title>Running a simple dotnet Core Linux daemon</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;p&gt;Someone has asked me about running a dotnet Core service as a Linux daemon, this is a very trivial example&lt;/p&gt;

&lt;p&gt;Running a ASP.NET service should be much the same, as all project types result in console applications, so the generated project’s main method will include a blocking call on host.Run()&lt;/p&gt;

&lt;h2 id=&quot;environment&quot;&gt;Environment&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Ubuntu 16.04 using &lt;a href=&quot;https://www.freedesktop.org/wiki/Software/systemd/&quot;&gt;SystemD&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;dotnet &lt;a href=&quot;https://www.microsoft.com/net/download/linux&quot;&gt;Core&lt;/a&gt; 1.1&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;create-application&quot;&gt;Create application&lt;/h2&gt;
&lt;p&gt;This is just a simple console application that writes a message to stdout&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Create application
mkdir dnsvc
cd dnsvc
dotnet new console

# Change Program.cs
cat &amp;gt; Program.cs &amp;lt;&amp;lt;EOF
using System;
using System.Threading;


namespace dnsvc
{
  class Program
  {
    static void Main(
      string[] args)
    {
      var sleep = 3000;
      if (args.Length &amp;gt; 0) { int.TryParse(args[0], out sleep); }
      while (true)
      {
        Console.WriteLine($&quot;Working, pausing for {sleep}ms&quot;);
        Thread.Sleep(sleep);
      }
    }
  }
}
EOF

# Restore dependencies
dotnet restore

# Publish to a local bin sub directory
dotnet publish --configuration Release --output bin

# Run local to verify all is good
dotnet ./bin/dnsvc.dll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;create-systemd-service-file&quot;&gt;Create SystemD service file&lt;/h2&gt;
&lt;p&gt;Will run the application from the bin sub directory for now&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cat &amp;gt; dnsvc.service &amp;lt;&amp;lt;EOF
[Unit]
Description=Demo service
After=network.target

[Service]
ExecStart=/usr/bin/dotnet $(pwd)/bin/dnsvc.dll 5000
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configure-systemd-so-it-is-aware-of-the-new-service&quot;&gt;Configure SystemD so it is aware of the new service&lt;/h2&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Copy service file to a System location
sudo cp dnsvc.service /lib/systemd/system

# Reload SystemD and enable the service, so it will restart on reboots
sudo systemctl daemon-reload 
sudo systemctl enable dnsvc

# Start service
sudo systemctl start dnsvc 

# View service status
systemctl status dnsvc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;tail-the-service-log&quot;&gt;Tail the service log&lt;/h3&gt;
&lt;p&gt;Since we are just writing to stdout the output can be examined with &lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/journalctl.html&quot;&gt;journalctl&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;journalctl --unit dnsvc --follow
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;stopping-and-restarting-the-service&quot;&gt;Stopping and restarting the service&lt;/h2&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Stop service
sudo systemctl stop dnsvc 
systemctl status dnsvc 

# Restart the service
sudo systemctl start dnsvc 
systemctl status dnsvc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;cleaning-up&quot;&gt;Cleaning up&lt;/h1&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Ensure service is stopped
sudo systemctl stop dnsvc 

# Disable
sudo systemctl disable dnsvc 

# Remove and reload SystemD
sudo rm dnsvc.service /lib/systemd/system/dnsvc.service 
sudo systemctl daemon-reload 

# Verify SystemD is no longer aware of the service - Empty is what we want here
systemctl --type service |&amp;amp; grep dnsvc 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;gracefull-shutdown---handling-signals&quot;&gt;Gracefull shutdown - Handling signals&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;The service should handle &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_signal&quot;&gt;signals&lt;/a&gt; like SIGTERM, SIGINT etc.&lt;/li&gt;
  &lt;li&gt;Would use this to do any cleanup just before exiting, like docker &lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/stop/&quot;&gt;stop&lt;/a&gt; for containers&lt;/li&gt;
  &lt;li&gt;Current version of dotnet Core does NOT handle this as far as I know&lt;/li&gt;
  &lt;li&gt;You can follow this &lt;a href=&quot;https://github.com/dotnet/coreclr/pull/4309&quot;&gt;issue&lt;/a&gt;, should hopefully be sorted in the near future&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 05 Apr 2017 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/running-a-simple-dotnet-core-linux-daemon</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/running-a-simple-dotnet-core-linux-daemon</guid>
        
        
        <category>dotnetcore</category>
        
      </item>
    
      <item>
        <title>Using KMS in the shell</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;p&gt;Some notes on using AWS KMS from the shell&lt;/p&gt;

&lt;h3 id=&quot;create-an-aws-customer-master-key-if-you-do-not-already-have-one&quot;&gt;Create an AWS &lt;a href=&quot;http://docs.aws.amazon.com/cli/latest/reference/kms/create-key.html&quot;&gt;customer master key&lt;/a&gt; if you do not already have one&lt;/h3&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;key_id=$(aws kms create-key | jq -r .KeyMetadata.KeyId)
aws kms create-alias --alias-name alias/my-test-key --target-key-id $key_id
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;policy&quot;&gt;Policy&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;You should use policy to restrict access to the key&lt;/li&gt;
  &lt;li&gt;In this sample I presume you have access to the key&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;script-with-encryptdecrypt-and-some-test-functions&quot;&gt;Script with encrypt\decrypt and some test functions&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# This assumes you have configured the AWS region and credentials, if not it will fail&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# We do not set errexit or pipefail as the environment sourcing this should configure this&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Can use set -o to check&lt;/span&gt;

kms-decrypt&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$AWS_REGION&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

	aws kms decrypt &lt;span class=&quot;nt&quot;&gt;--ciphertext-blob&lt;/span&gt; fileb://&amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cipher&lt;/span&gt; | base64 &lt;span class=&quot;nt&quot;&gt;--decode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--region&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$region&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; text &lt;span class=&quot;nt&quot;&gt;--query&lt;/span&gt; Plaintext | base64 &lt;span class=&quot;nt&quot;&gt;--decode&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

kms-encrypt&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;plain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$3&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$AWS_REGION&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

	aws kms encrypt &lt;span class=&quot;nt&quot;&gt;--key-id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--plaintext&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$plain&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--region&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$region&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; text &lt;span class=&quot;nt&quot;&gt;--query&lt;/span&gt; CiphertextBlob
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Tests&lt;/span&gt;
assert&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# If you have set errexit this will fail and exit immediately, should test with set +o errexit&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-eq&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\e&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[32m&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;FUNCNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[1]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; passed&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\e&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[0m&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\e&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[31m &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;FUNCNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[1]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; failed&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\e&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[0m&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

test-kms-roundtrip-with-no-context&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;my-test-key
	&lt;span class=&quot;nv&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;original_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'eykjsgh$^%46546112--dff09865-END'&lt;/span&gt;

	&lt;span class=&quot;nv&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;kms-encrypt &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$context&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$original_data&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;plain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;kms-decrypt &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$context&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cipher&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;

	assert &lt;span class=&quot;s2&quot;&gt;&quot;[ '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$original_data&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' == '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$plain&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' ]&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

test-kms-roundtrip-with-context&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;my-test-key
	&lt;span class=&quot;nv&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'k1=v1,k2=v2'&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;original_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'eykjsgh$^%46546112--dff09865-OTHER-END.'&lt;/span&gt;

	&lt;span class=&quot;nv&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;kms-encrypt &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$context&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$original_data&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;plain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;kms-decrypt &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$context&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cipher&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;

	assert &lt;span class=&quot;s2&quot;&gt;&quot;[ '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$original_data&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' == '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$plain&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' ]&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Mon, 20 Feb 2017 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/using-kms-in-the-shell</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/using-kms-in-the-shell</guid>
        
        
        <category>aws</category>
        
      </item>
    
      <item>
        <title>Getting started with Clojure</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;p&gt;These are just a couple of pointers for getting started with Clojure, as I have been asked this question and I know when I started I would have appreciated the same content.
I am new enough to Clojure so this content is based on my current understanding.
This post will explain how to get an Ubuntu linux JVM environment up and running so we can explore Clojure. 
You should be able to setup an environment on other OSes by using the equivalent OS commands.&lt;/p&gt;

&lt;h2 id=&quot;what-is-clojure&quot;&gt;What is Clojure&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Clojure&quot;&gt;Clojure&lt;/a&gt; is a dialect of the Lisp programming language. It is a dynamic functional language that runs in a hosted environment. 
The most popular hosted environment is the JVM. There are versions which can be hosted on other environments, see &lt;a href=&quot;https://github.com/clojure/clojure-clr&quot;&gt;CLR&lt;/a&gt; and &lt;a href=&quot;https://github.com/clojure/clojurescript&quot;&gt;JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;/h2&gt;
&lt;p&gt;You can use the offical docker &lt;a href=&quot;https://registry.hub.docker.com/_/clojure/&quot;&gt;image&lt;/a&gt; which will have the pre-requisites already installed.&lt;/p&gt;

&lt;h2 id=&quot;pre-requisites&quot;&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;This section will describe setting up your local machine, if you are using the docker image this does not apply.&lt;/p&gt;

&lt;h3 id=&quot;jvm&quot;&gt;JVM&lt;/h3&gt;
&lt;p&gt;JVM - Ensure we have a JVM, so we have a hosted environment for Clojure. Clojure currently requires Java 1.6 or greater.
You can check if you already have Java and which JVM using the following&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Do I already have Java ?&lt;/span&gt;
which java

&lt;span class=&quot;c&quot;&gt;# Which Java to I already have ?&lt;/span&gt;
dpkg &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;readlink &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;which java&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you need to install Java, there are many &lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_Java_virtual_machines&quot;&gt;JVMs&lt;/a&gt;, I will use OpenJDK 7&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Ensure our package lists are up to date&lt;/span&gt;
apt-get update

&lt;span class=&quot;c&quot;&gt;# Install OpenJDK 7&lt;/span&gt;
apt-get install &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; openjdk-7-jdk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;minimal-clojure-usage&quot;&gt;Minimal Clojure usage&lt;/h2&gt;
&lt;p&gt;Since we already have a JVM, we just need the Clojure JAR itself. Clojure is just another Java package.&lt;/p&gt;
&lt;h3 id=&quot;get-clojure-jar-extracting-to-a-temp-directory&quot;&gt;Get Clojure JAR extracting to a temp directory&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Make temp directory in /tmp and change to this directory - This directory will be deleted by the OS in time&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;dir_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;mktemp &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dir_name&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Download jar - its in a zip file so we need to extract (Requires unzip utility)&lt;/span&gt;
wget http://repo1.maven.org/maven2/org/clojure/clojure/1.6.0/clojure-1.6.0.zip
unzip clojure-1.6.0.zip 

&lt;span class=&quot;c&quot;&gt;# Copy JAR to this directory&lt;/span&gt;
cp clojure-1.6.0/clojure-1.6.0.jar &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;start-a-repl&quot;&gt;Start a REPL&lt;/h3&gt;
&lt;p&gt;A REPL is a read eval print loop that allows interactive programming. Ruby has irb, erlang has erl etc.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Run java with clojure-1.6.0.jar in the classpath and execute clojure.main entry point&lt;/span&gt;
java &lt;span class=&quot;nt&quot;&gt;-cp&lt;/span&gt; clojure-1.6.0.jar clojure.main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can now execute Clojure expressions such as (+ 1 2) which will be evaluated and the result of the expression will be printed.
Ctrl-d to exit the REPL.&lt;/p&gt;

&lt;h3 id=&quot;run-a-program&quot;&gt;Run a program&lt;/h3&gt;
&lt;p&gt;You can run a program - silly example but just to illustrate&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create app.clj file which just prints Hello world&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'(println &quot;Hello world&quot;)'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; app.clj

&lt;span class=&quot;c&quot;&gt;# Run program&lt;/span&gt;
java &lt;span class=&quot;nt&quot;&gt;-cp&lt;/span&gt; clojure-1.6.0.jar clojure.main app.clj
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;leiningen&quot;&gt;leiningen&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://leiningen.org/&quot;&gt;leiningen&lt;/a&gt; seems to be the most popular way to manage Clojure code.
The &lt;a href=&quot;https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md&quot;&gt;tutorial&lt;/a&gt; details the functions and extensions that this tool provides.
Some of the features you can use it for&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Installing Clojure (Let it manage this rather than using the minimal Clojure usage described above)&lt;/li&gt;
  &lt;li&gt;Creating projects - Like scaffolding in other enviornments (Ruby on Rails, ASP.NET)&lt;/li&gt;
  &lt;li&gt;Directory layout standardisation&lt;/li&gt;
  &lt;li&gt;Managing dependencies (Like Bundler, go get, nuget etc)&lt;/li&gt;
  &lt;li&gt;Running a REPL&lt;/li&gt;
  &lt;li&gt;Running the application&lt;/li&gt;
  &lt;li&gt;Running tests&lt;/li&gt;
  &lt;li&gt;Builds (Building a single application Uberjar)&lt;/li&gt;
  &lt;li&gt;Plugins (Like managing ClojureScript builds)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;
&lt;p&gt;See the projet &lt;a href=&quot;http://leiningen.org/&quot;&gt;site&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create bin directory if it does not already exist&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; ~/bin &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; mkdir ~/bin

&lt;span class=&quot;c&quot;&gt;# Get leiningen script and make executable&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/bin
wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
chmod +x ~/bin/lein

&lt;span class=&quot;c&quot;&gt;# May need to exit and reload shell if bin directory did not already exist so it will be on the path&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# See ~/.profile which should add ~/bin to path if it exists&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Run lein - Will download and self-install the leiningen package&lt;/span&gt;
lein 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;basic-hello-world-application&quot;&gt;Basic hello world application&lt;/h2&gt;
&lt;p&gt;Create new app (With a main function so it can be run from the command line), this uses the app template to create a main entry point function.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create new app&lt;/span&gt;
lein new app hello
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;hello

&lt;span class=&quot;c&quot;&gt;# List all files excluding target directory content&lt;/span&gt;
find &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;nt&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-path&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'./target/*'&lt;/span&gt; | sort
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./doc/intro.md
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./.gitignore
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./.hgignore
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./LICENSE
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./project.clj
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./README.md
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./src/hello/core.clj
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./test/hello/core_test.clj

&lt;span class=&quot;c&quot;&gt;# Run app &lt;/span&gt;
lein run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The important files are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;src/hello/core.clj - This file contains code, and the entry point function main&lt;/li&gt;
  &lt;li&gt;test/hello/core.clj - This file contains a test, the test will fail until corrected&lt;/li&gt;
  &lt;li&gt;project.clj - This file contains project attributes, dependencies, leiningen plugins etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;repl&quot;&gt;REPL&lt;/h2&gt;
&lt;p&gt;You can start a REPL using&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lein repl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;This will start a REPL and switch to the “hello.core” namespace.&lt;/li&gt;
  &lt;li&gt;All of the dependencies in the project.clj will be available, they will all be included in the classpath and can be required.&lt;/li&gt;
  &lt;li&gt;You can execute functions that have been defined.&lt;/li&gt;
  &lt;li&gt;You can run tests that have been defined.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run already defined functions within the same REPL&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;; Execute the -main function which is defined in the src/hello/core.clj file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To run the test function that was created (This is a sample that is set to fail) within the same REPL&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;; Require namespaces&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;'clojure.test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;'hello.core-test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;; Execute the run-tests function for the test namespace&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;clojure.test/run-tests&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;'hello.core-test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can also see the documentation and source for functions within the repl as follows&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;; Get the documentation for the map function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;; Get the source for the map function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;basic-hello-world-web-app&quot;&gt;Basic hello world web app&lt;/h2&gt;
&lt;p&gt;Create new app, this will create a library app that does not have a main entry function&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create new app&lt;/span&gt;
lein new helloweb
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;helloweb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Alter the project.clj as follows&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defproject&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helloweb&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.1.0-SNAPSHOT&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:description&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FIXME: write description&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/FIXME&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:license&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Eclipse Public License&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:dependencies&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.clojure/clojure&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.6.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ring/ring-core&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.3.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:plugins&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lein-ring&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.8.13&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:ring&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:handler&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helloweb.core/handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;We have added an extra dependency &lt;a href=&quot;https://github.com/ring-clojure/ring&quot;&gt;ring-core&lt;/a&gt; v1.3.2&lt;/li&gt;
  &lt;li&gt;We have added an extra leiningen plugin lein-ring v0.8.13&lt;/li&gt;
  &lt;li&gt;We have added an extra ring attribute indicating the handler to use - this will be the entry point for the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ring is the Clojure equivalent of &lt;a href=&quot;http://rack.github.io/&quot;&gt;Rack&lt;/a&gt; for Ruby or &lt;a href=&quot;http://owin.org/&quot;&gt;OWIN&lt;/a&gt; for .NET.
Ring provides a minimal interface between webservers and web application frameworks or implementations.&lt;/p&gt;

&lt;p&gt;Alter the src/helloweb/core.clj as follows&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helloweb.core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;; Single function that responds to all request as we have no routing configured&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:headers&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;We have removed the default function that gets added when lein new was invoked.&lt;/li&gt;
  &lt;li&gt;We have added a new function named handler and we take a single request parameter and return a map that ring expects (status, headers and body).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the app with the following, note we are using the ring plugin&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lein ring server-headless
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will open your default browser on localhost port 3000, serving the content.&lt;/p&gt;

&lt;p&gt;To see the http content open another terminal and run&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\n'&lt;/span&gt; http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a very basic web app and there are much richer tools for creating web apps\api applications, such as &lt;a href=&quot;https://github.com/weavejester/compojure&quot;&gt;Compojure&lt;/a&gt; and &lt;a href=&quot;http://www.luminusweb.net/&quot;&gt;Luminus&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;editors&quot;&gt;Editors&lt;/h1&gt;
&lt;p&gt;I am currently using vim with no plugins but there are vim plugins for clojure and most people seem to be using emacs.&lt;/p&gt;

&lt;h1 id=&quot;running-tests&quot;&gt;Running tests&lt;/h1&gt;
&lt;p&gt;You can run tests that are defined in the test directory using the following&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lein &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since we didn’t change the test included when we created the app this will fail.&lt;/p&gt;

&lt;h2 id=&quot;good-online-resources-for-getting-started&quot;&gt;Good online resources for getting started&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.braveclojure.com/&quot;&gt;CLOJURE for the BRAVE and TRUE&lt;/a&gt; - Very good sieries of blog entries that you can also buy as a book&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://aphyr.com/tags/Clojure-from-the-ground-up&quot;&gt;Clojure from the ground up&lt;/a&gt; - Very good series of blog entries&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matthiasn/Clojure-Resources&quot;&gt;Mathias’s&lt;/a&gt; list of learning resources&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bbatsov/clojure-style-guide&quot;&gt;Styleguide&lt;/a&gt; which helps with understanding code layout&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 19 Mar 2015 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/getting-started-with-clojure</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/getting-started-with-clojure</guid>
        
        
        <category>clojure</category>
        
      </item>
    
      <item>
        <title>Running an etcd cluster on localhost</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Run a cluster on localhost while investigating etcd&lt;/li&gt;
  &lt;li&gt;Use a &lt;a href=&quot;https://github.com/coreos/etcd/blob/master/Documentation/clustering.md#static&quot;&gt;static&lt;/a&gt; cluster (So we have no external dependecies for bootstrapping)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;background-information&quot;&gt;Background information&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;etcd &lt;a href=&quot;https://github.com/coreos/etcd&quot;&gt;source&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-use-etcdctl-and-etcd-coreos-s-distributed-key-value-stor://www.digitalocean.com/community/tutorials/how-to-use-etcdctl-and-etcd-coreos-s-distributed-key-value-store&quot;&gt;How to use etcdctl and etcd coreos’s distributed key value store&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;etcd &lt;a href=&quot;https://github.com/coreos/etcd/blob/master/Documentation/clustering.md&quot;&gt;clustering&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;etcd &lt;a href=&quot;https://github.com/coreos/etcd/tree/master/Documentation&quot;&gt;documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.consul.io/&quot;&gt;Consul&lt;/a&gt; which is a very popular alternative&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bootstrap&quot;&gt;Bootstrap&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Will use static bootstrapping&lt;/li&gt;
  &lt;li&gt;Client connection port default is 2379 (Just supporting a single port per node), we will decerement the port for subsequent nodes so we do not get a port conflict&lt;/li&gt;
  &lt;li&gt;Peer connection (Raft consensus) port default is 2380 (Just supporting a single port per node), we will increment the port for subsequent nodes so we do not get a port conflict&lt;/li&gt;
  &lt;li&gt;Will use /tmp/etcdinv directory for the cluster - If you want the cluster to stick around use a different directory
    &lt;ul&gt;
      &lt;li&gt;If all nodes are stopped and then restarted the cluster will try to restart with this state, if the OS has not already purged this content&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Will write node logs to a file and run process in the background&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# etcd bin directory&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;etcd_bin_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/home/pmcgrath/go/src/github.com/coreos/etcd/bin/

&lt;span class=&quot;c&quot;&gt;# Ensure we have a root directory for the cluster - Note we are using /tmp here, if you want the cluster to stick arounf use a different directory&lt;/span&gt;
mkdir &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /tmp/etcdinv

&lt;span class=&quot;c&quot;&gt;# Run node 1 &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcd &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; node1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-data-dir&lt;/span&gt; /tmp/ectdinv/node1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-peer-urls&lt;/span&gt; http://localhost:2380 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-client-urls&lt;/span&gt; http://localhost:2379 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-advertise-peer-urls&lt;/span&gt; http://localhost:2380 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster-token&lt;/span&gt; MyEtcdCluster &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;node1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2380,node2&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2381,node3&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2382 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster-state&lt;/span&gt; new &amp;amp;&amp;gt; /tmp/etcdinv/node1.log &amp;amp;

&lt;span class=&quot;c&quot;&gt;# Run node 2 &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcd &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; node2 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-data-dir&lt;/span&gt; /tmp/ectdinv/node2 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-peer-urls&lt;/span&gt; http://localhost:2381 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-client-urls&lt;/span&gt; http://localhost:2378 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-advertise-peer-urls&lt;/span&gt; http://localhost:2381 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster-token&lt;/span&gt; MyEtcdCluster &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;node1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2380,node2&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2381,node3&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2382 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster-state&lt;/span&gt; new &amp;amp;&amp;gt; /tmp/etcdinv/node2.log &amp;amp;

&lt;span class=&quot;c&quot;&gt;# Run node 3 &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcd &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; node3 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-data-dir&lt;/span&gt; /tmp/ectdinv/node3 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-peer-urls&lt;/span&gt; http://localhost:2382 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-client-urls&lt;/span&gt; http://localhost:2377 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-advertise-peer-urls&lt;/span&gt; http://localhost:2382 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster-token&lt;/span&gt; MyEtcdCluster &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;node1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2380,node2&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2381,node3&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2382 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster-state&lt;/span&gt; new &amp;amp;&amp;gt; /tmp/etcdinv/node3.log &amp;amp;

&lt;span class=&quot;c&quot;&gt;# List nodes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2379 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl member list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;You can see the cluster node pids using
    &lt;ul&gt;
      &lt;li&gt;pidof etcd&lt;/li&gt;
      &lt;li&gt;
        &lt;table&gt;
          &lt;tbody&gt;
            &lt;tr&gt;
              &lt;td&gt;ps aux&lt;/td&gt;
              &lt;td&gt;grep etcd&lt;/td&gt;
            &lt;/tr&gt;
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;interacting-with-the-cluster-using-etcdctl&quot;&gt;Interacting with the cluster using etcdctl&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Will use the client port 2379 based on &lt;a href=&quot;http://www.iana.org/assignments/service-names-port-numbers&quot;&gt;this&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;etcdctl defaults to 4001 at this time&lt;/li&gt;
  &lt;li&gt;I could have added an extra client url for 4001 when bring up the nodes, but I’m guessing 4001 will be removed at some stage&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# etcd bin directory&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;etcd_bin_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/home/pmcgrath/go/src/github.com/coreos/etcd/bin/

&lt;span class=&quot;c&quot;&gt;# Using node1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Write a key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2379 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; /dir1/key1 value1
&lt;span class=&quot;c&quot;&gt;# Should echo value1&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Read key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2379 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should echo value1&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Using node3&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Read key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2377 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should echo value1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;kill-one-of-the-nodes&quot;&gt;Kill one of the nodes&lt;/h2&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# etcd bin directory&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;etcd_bin_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/home/pmcgrath/go/src/github.com/coreos/etcd/bin/

&lt;span class=&quot;c&quot;&gt;# Kill node2&lt;/span&gt;
pidof etcd
&lt;span class=&quot;c&quot;&gt;# Should only have 3 pids&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;kill&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;ps aux | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'etcd \-name node2'&lt;/span&gt; | cut &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; 2&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
pidof etcd
&lt;span class=&quot;c&quot;&gt;# Should only have 2 pids&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Read key using node1&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2379 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should echo value1&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Read key using node2&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2378 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should fail indicating cluster node could not available &lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Read key using node3&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:2377 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should echo value1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;using-a-proxy&quot;&gt;Using a proxy&lt;/h2&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# etcd bin directory&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;etcd_bin_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/home/pmcgrath/go/src/github.com/coreos/etcd/bin/

&lt;span class=&quot;c&quot;&gt;# Run a read write proxy - on 8080 &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcd &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-proxy&lt;/span&gt; on &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; proxy &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-listen-client-urls&lt;/span&gt; http://localhost:8080 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;-initial-cluster&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;node1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2380,node2&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2381,node3&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:2382 &amp;amp;&amp;gt; /tmp/etcdinv/proxy.log &amp;amp;

&lt;span class=&quot;c&quot;&gt;# Read existing key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:8080 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should echo value1&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Write a key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:8080 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; /dir1/key2 value2
&lt;span class=&quot;c&quot;&gt;# Should echo value2&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Read existing key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ETCDCTL_PEERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:8080 &lt;span class=&quot;nv&quot;&gt;$etcd_bin_dir&lt;/span&gt;/etcdctl get /dir1/key1
&lt;span class=&quot;c&quot;&gt;# Should echo value2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Thu, 15 Jan 2015 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/running-an-etcd-cluster-on-localhost</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/running-an-etcd-cluster-on-localhost</guid>
        
        
        <category>docker</category>
        
        <category>etcd</category>
        
      </item>
    
      <item>
        <title>Managing golang dependencies</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;This is how I currently manage my golang dependencies (vendoring)&lt;/li&gt;
  &lt;li&gt;I currently use the &lt;a href=&quot;https://github.com/tools/godep&quot;&gt;godep&lt;/a&gt; tool&lt;/li&gt;
  &lt;li&gt;This post is just to remind me of a couple of things that are not pointed out in the godep documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;See the offiicial golang &lt;a href=&quot;http://golang.org/doc/faq#get_version&quot;&gt;faq&lt;/a&gt; for their view on dependency management&lt;/li&gt;
  &lt;li&gt;See package management tool choices &lt;a href=&quot;https://github.com/golang/go/wiki/PackageManagementTools&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;To understand how godep works read the &lt;a href=&quot;https://github.com/tools/godep&quot;&gt;readme&lt;/a&gt;, this content is just some extra stuff I keep having to remember&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;commit-dependencies&quot;&gt;Commit dependencies&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;godep now indicates the Godeps sub directory should be commited&lt;/li&gt;
  &lt;li&gt;There is a .gitignore file with entries for the bin and pkg directories within the workspace directory, so only the source is commited&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;relying-on-specific-dependency-versions&quot;&gt;Relying on specific dependency versions&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;When you first take the dependencies using the “godep save” command it records the current versions of the dependencies&lt;/li&gt;
  &lt;li&gt;If you need to use a specific branch or version of one of the dependencies you should check that out before running the “godep save” command&lt;/li&gt;
  &lt;li&gt;If you have already taken the dependencies using the “godep save” command, you can always checkout a specific version of a dependency and then run “godep update” for the dependency&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;updating-specific-dependencies&quot;&gt;Updating specific dependencies&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;As indicated in the godep readme, run the “godep update” command&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;buildinginstallingrunning&quot;&gt;Building\Installing\Running&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Use godep so you are in fact using the vendored versions rather then the cloned versions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;http://blog.gopheracademy.com/advent-2014/deps/&lt;/li&gt;
  &lt;li&gt;http://nathany.com/go-packages/&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Fri, 07 Nov 2014 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/managing-golang-dependencies</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/managing-golang-dependencies</guid>
        
        
        <category>golang</category>
        
      </item>
    
      <item>
        <title>How to get golang package import list</title>
        <description>&lt;p&gt;This &lt;a href=&quot;https://golang.org/cmd/go/#hdr-List_packages&quot;&gt;page&lt;/a&gt; contains the data that is available to the go list command, we use golang templates to extract subsets of this data below&lt;/p&gt;

&lt;h2 id=&quot;get-imports-for-the-current-directory-package&quot;&gt;Get imports for the current directory package&lt;/h2&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
go list &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{{range $imp := .Imports}}{{printf &quot;%s\n&quot; $imp}}{{end}}'&lt;/span&gt; | sort

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This lists all the imports for the current package&lt;/p&gt;

&lt;h2 id=&quot;get-list-of-non-standard-dependencies&quot;&gt;Get list of non standard dependencies&lt;/h2&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
go list &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{{range $dep := .Deps}}{{printf &quot;%s\n&quot; $dep}}{{end}}'&lt;/span&gt; | xargs go list &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{{if not .Standard}}{{.ImportPath}}{{end}}'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This lists all the non standard dependencies for the current package&lt;/p&gt;

</description>
        <pubDate>Tue, 21 Oct 2014 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/how-to-get-golang-package-import-list</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/how-to-get-golang-package-import-list</guid>
        
        
        <category>golang</category>
        
      </item>
    
      <item>
        <title>Raw content in Jekyll markdown</title>
        <description>&lt;p&gt;This is an issue when including golang template and angular content in markdown, both of which use {{ and }}&lt;br /&gt;
You need to surround the content with the {%raw%} and {%endraw%} tags&lt;/p&gt;

&lt;p&gt;i.e. for a golang program using a text template&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/template&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ted&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;His name is {{.Name}}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;the issue is with the “His name is {{.Name}}\n” parameter to the template’s Parse method, you can&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Surround the entire content with {%raw%} and {%endraw%} tags, less work&lt;/li&gt;
  &lt;li&gt;Surround only the piece that causes the issue with {%raw%} and {%endraw%} tags&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;surround-the-entire-content-with-raw-and-endraw-tags&quot;&gt;Surround the entire content with {%raw%} and {%endraw%} tags&lt;/h3&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/template&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ted&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;His name is {{.Name}}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endraw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;surround-only-the-piece-that-causes-the-issue-with-raw-and-endraw-tags&quot;&gt;Surround only the piece that causes the issue with {%raw%} and {%endraw%} tags&lt;/h3&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/template&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ted&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;His name is {%raw%}{{.Name}}{%endraw%}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sat, 11 Oct 2014 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/raw-content-in-jekyll-markdown</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/raw-content-in-jekyll-markdown</guid>
        
        
        <category>jekyll</category>
        
        <category>markdown</category>
        
      </item>
    
      <item>
        <title>Docker inspect data subsets</title>
        <description>&lt;h2 id=&quot;inspect-the-state-of-a-docker-container&quot;&gt;Inspect the state of a docker container&lt;/h2&gt;
&lt;p&gt;You can inspect the state of a container using the following command&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;cid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;REPLACE_THIS_WITH_THE_CONTAINER_ID_OR_NAME
docker inspect &lt;span class=&quot;nv&quot;&gt;$cid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;this returns a json document with comprehensive information on the container. This information can be manipulated using a tool like &lt;a href=&quot;http://stedolan.github.io/jq/&quot;&gt;jq&lt;/a&gt; on the command line.&lt;/p&gt;

&lt;h2 id=&quot;using-docker-inspect-templates-to-get-a-subset-of-the-data&quot;&gt;Using docker inspect templates to get a subset of the data&lt;/h2&gt;
&lt;p&gt;If you use the -f argument when calling docker inspect you can use a golang &lt;a href=&quot;http://golang.org/pkg/text/template/&quot;&gt;template&lt;/a&gt; to control the content that gets emmited, the following are some samples&lt;/p&gt;

&lt;h3 id=&quot;get-the-container-process-pid&quot;&gt;Get the container process pid&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;cid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;REPLACE_THIS_WITH_THE_CONTAINER_ID_OR_NAME
docker inspect &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{{ .State.Pid }}'&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cid&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 32109
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;docker is passing the result of the object returned from a full docker inspect command to the ‘{{ .State.Pid }}’ go text template, it is then accessing state within the object using that first “.” so we can do print anything we like&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;cid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;REPLACE_THIS_WITH_THE_CONTAINER_ID_OR_NAME
docker inspect &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'The process id is {{ .State.Pid }}'&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cid&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; The process id is 32109
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;script-to-echo-some-high-level-info-that-is-not-included-in-docker-ps-command-output&quot;&gt;Script to echo some high level info that is not included in “docker ps” command output&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Containers to run for - default is all, if none passed&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-eq&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker ps &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# See http://golang.org/pkg/text/template/&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Id: {{.Id}}
Name: {{.Name}}
Image: {{.Image}}
Pid: {{.State.Pid}}
IP: {{.NetworkSettings.IPAddress}}
Host: {{.Config.Hostname}}
EntryPoint: {{.Config.Entrypoint}}
Command: {{.Config.Cmd}}
Ports: {{range $key, $value := .Config.ExposedPorts}}{{$key}} {{end}}
Links: {{range .HostConfig.Links}}{{.}} {{end}}
Volumes: {{if .Volumes}}{{range $key, $value := .Volumes}}
  {{$key}} -&amp;gt; {{$value}}{{end}}{{end}}
'&lt;/span&gt;
docker inspect &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$template&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$containers&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sat, 11 Oct 2014 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/docker-inspect-data-subsets</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/docker-inspect-data-subsets</guid>
        
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Include version information in a golang application</title>
        <description>&lt;h2 id=&quot;purpose&quot;&gt;Purpose&lt;/h2&gt;
&lt;p&gt;Include some version information in a golang application when building it&lt;br /&gt;
See &lt;a href=&quot;https://github.com/docker/docker&quot;&gt;docker&lt;/a&gt;, &lt;a href=&quot;https://github.com/drone/drone&quot;&gt;drone&lt;/a&gt; etc. where you can run a version command and see this information&lt;/p&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;See golang &lt;a href=&quot;http://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies&quot;&gt;build&lt;/a&gt; command’s -ldflags argument&lt;/li&gt;
  &lt;li&gt;More detailed information is &lt;a href=&quot;http://golang.org/cmd/ld/&quot;&gt;here&lt;/a&gt; see the -X option&lt;/li&gt;
  &lt;li&gt;So we can pass name value pairs when building or installing an application&lt;/li&gt;
  &lt;li&gt;If we use keys that are of the format importpath.name we will be able to set string vars when building the package for the application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;golang-app&quot;&gt;golang app&lt;/h2&gt;
&lt;p&gt;Save this in /tmp/app/main.go&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builtAt&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builtBy&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builtOn&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Version info :: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;commit: %s &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;built @ %s by %s on %s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builtAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builtBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builtOn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

	&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// Do work&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;buildinstall-the-application&quot;&gt;Build\install the application&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;git rev-parse &lt;span class=&quot;nt&quot;&gt;--short&lt;/span&gt; HEAD&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;built_at&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;date +%FT%T%z&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;built_by&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;USER&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;built_on&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;hostname&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
 
go build &lt;span class=&quot;nt&quot;&gt;-ldflags&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-X main.commit &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; -X main.builtAt '&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;built_at&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' -X main.builtBy &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;built_by&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; -X main.builtOn &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;built_on&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;So we just pass each of our key values in the form “-X key value” in the -ldflags argument&lt;/li&gt;
  &lt;li&gt;The -ldflags argument can be used for go build, go run and go install commands&lt;/li&gt;
  &lt;li&gt;Any values that include white space will need to surround with extra quotes, see buildAt above&lt;/li&gt;
  &lt;li&gt;The keys match the importpath.name format&lt;/li&gt;
  &lt;li&gt;The passed values will override the initial values in the source&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;run-the-application&quot;&gt;Run the application&lt;/h2&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./app
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;Version info :: commit: de31196 built @ 2014-12-05T18:01:31+0000 by pmcgrath on Inspiron-7520
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;can-set-other-package-values&quot;&gt;Can set other package values&lt;/h2&gt;
&lt;p&gt;To see the list of options run “go tool nm app”&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Sep 2014 00:00:00 +0000</pubDate>
        <link>https://pmcgrath.github.io/include-version-information-in-golang-app</link>
        <guid isPermaLink="true">https://pmcgrath.github.io/include-version-information-in-golang-app</guid>
        
        
        <category>golang</category>
        
      </item>
    
  </channel>
</rss>
