Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28070817c2 | ||
|
|
c9376c4275 | ||
|
|
96de055b12 | ||
|
|
13bce6144c | ||
|
|
c9d06e0b5a | ||
|
|
02189faab0 | ||
|
|
916ee92f90 | ||
|
|
8af93058df | ||
|
|
2d30049c4e | ||
|
|
07f65b10e9 |
No files matched your search
@@ -0,0 +1,8 @@
|
||||
# Normalize text files to LF in the repo and working tree (matches Overleaf).
|
||||
* text=auto eol=lf
|
||||
|
||||
# Binary assets: never convert.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.pdf binary
|
||||
@@ -22,3 +22,6 @@
|
||||
*.lot
|
||||
*.lol
|
||||
*.pdf
|
||||
!figures/*.pdf
|
||||
*.data.minted
|
||||
_minted*/
|
||||
@@ -9,8 +9,10 @@ in the detail needed for a reviewer to see what was requested, what was
|
||||
returned, and what the author changed. Assistance was used for interpreting the
|
||||
assignment brief, drafting chapter text, and reviewing the document for internal
|
||||
consistency. It was not used to generate command output, evidence, or any claim
|
||||
about work that was not performed. No credential, key, or personal data was
|
||||
supplied to the tool. Every decision recorded below was made by the author; the assistant's role was
|
||||
about work that was not performed. No passwords, access tokens, private keys, or recovery codes were supplied.
|
||||
The supplied coursework evidence includes author names, local usernames, host
|
||||
names, and the local network details visible in the terminal captures.
|
||||
Every decision recorded below was made by the authors; the assistant's role was
|
||||
to propose and to check.
|
||||
|
||||
\section{Records}
|
||||
@@ -47,3 +49,93 @@ split of accounts into generated and derived classes.\\
|
||||
and work-in-progress criteria, and rejected a proposal to create a GitHub
|
||||
organization as premature while teams remain unformalized. Much of the assistant's
|
||||
wording, structure, and ambitious ideas were rejected for overcomplication.
|
||||
|
||||
\subsection{Record 3 --- Linux Commands}
|
||||
\textbf{Date:} September 26, 2026.\\
|
||||
\textbf{Tool and model:} Anthropic Claude (Opus 5).\\
|
||||
\textbf{Task}: Draft a template for \ChapterRef{LinuxCommands} with appropriate formatting
|
||||
for terminal inputs and outputs, and a structure for the problem set solutions. Revise
|
||||
the entire document to reflect the new chapter and team formation.\\
|
||||
\textbf{Inputs:} The document template and the Linux problem set.\\
|
||||
\textbf{Output used:} A skeleton of the chapter with its sections, setup figure, and
|
||||
the problem set headings for each question. Suggested edits to the metadata, abstract, and
|
||||
introduction for Assignment~2 and the two-person team.\\
|
||||
\textbf{Human review and corrections:} The authors refined the chapter structure to accommodate
|
||||
rubric requirements and experimented with different figure formatting for terminal inputs and outputs.
|
||||
|
||||
\subsection{Record 4 --- Guided Execution and Evidence Integration}
|
||||
\textbf{Dates:} September 27, 2026.\\
|
||||
\textbf{Tool:} OpenAI Codex.\\
|
||||
\textbf{Task:} Guide Victor through the Linux setup and Q1--Q40, check supplied
|
||||
results against the assignment, review the group chapter, and integrate evidence
|
||||
and concise explanations while preserving Payton's existing work.\\
|
||||
\textbf{Inputs:} Assignment and problem-set PDFs, the group PDF, supplied
|
||||
chapter and supporting LaTeX files, Victor's screenshots, and his terminal
|
||||
transcript.\\
|
||||
\textbf{Output used:} Command guidance; evidence checks; revised environment
|
||||
description; per-question explanations; labeled terminal screenshots; Q15/Q20
|
||||
clarifications; explicit Q38 assumptions; history and version updates.\\
|
||||
\textbf{Human contribution and review:} Victor executed the commands and supplied
|
||||
the resulting screenshots and transcript. Payton supplied the existing setup
|
||||
figures and problem-set answers. Codex edited the documentation and checked it
|
||||
against the recorded results; it did not generate substitute execution output.
|
||||
The team remains responsible for reviewing the additions and compiling the
|
||||
combined Overleaf project.\\
|
||||
|
||||
\subsection{Record 5 --- AWS Deployment and Proposal Draft}
|
||||
\textbf{Dates:} October 1--5, 2026.\\
|
||||
\textbf{Tool:} OpenAI Codex.\\
|
||||
\textbf{Task:} Guide Victor through AWS account access, EC2 provisioning,
|
||||
class-based website development, Docker installation and deployment, then draft
|
||||
his chapter from the actual sources and screenshots.\\
|
||||
\textbf{Human contribution:} Victor operated AWS, created the application
|
||||
files, executed local and remote commands, resolved the repository-key failure
|
||||
with guidance, and provided the execution screenshots. Payton is responsible
|
||||
for the separate TeX Live compiler exercise and chapter. Both authors will
|
||||
review the tool-comparison proposal.\\
|
||||
\textbf{Output used:} Command guidance, source code, saved evidence, deployment
|
||||
chapter, draft GitHub Actions/Jenkins proposal, metadata, and history updates.
|
||||
Codex copied additions into the student's supplied course repository location.\\
|
||||
\textbf{Review boundary:} Proposal selection requires team review. Payton's
|
||||
compiler work was not present in the inspected repository. Full compilation,
|
||||
combined report review, repository publication, and Canvas submission are not
|
||||
claimed by this record.
|
||||
|
||||
\subsection{Record 6 --- LaTeX Docker Chapter}
|
||||
\textbf{Dates:} October 5, 2026.\\
|
||||
\textbf{Tool and model:} Anthropic Claude (Opus 5.5).\\
|
||||
\textbf{Task:} Guide Payton through building a Docker container that compiles
|
||||
a \LaTeX\ document with TeX Live and draft \ChapterRef{LatexDocker};
|
||||
propose matching updates to the abstract, \ChapterRef{Introduction},
|
||||
\ChapterRef{Hosts}, glossary, metadata, and document history.\\
|
||||
\textbf{Inputs:} The assignment brief, Payton's terminal output and screenshots,
|
||||
and Overleaf's TeX Live documentation.\\
|
||||
\textbf{Output used:} The finalized Dockerfile, \texttt{.dockerignore}, and sample document;
|
||||
the chapter draft; proposed replacement text for outdated sections.\\
|
||||
\textbf{Human decisions and corrections:} Payton selected Debian's TeX Live packages,
|
||||
built and ran the container under WSL, supplied the evidence screenshots,
|
||||
and revised the chapter's organization and wording.\\
|
||||
\textbf{Review boundary:} The assistant compiled the full report with its own
|
||||
TeX Live installation to check the chapter; the image was built and
|
||||
run only by Payton. All execution evidence was produced by Payton. The assistant
|
||||
edited no repository files.
|
||||
|
||||
\subsection{Record 7 --- Inviscid Project Proposal}
|
||||
\textbf{Date:} October 6, 2026.\\
|
||||
\textbf{Tool:} OpenAI Codex.\\
|
||||
\textbf{Task:} Brainstorm Inviscid, refine the metrics-tool comparison and
|
||||
research question, and write the approved proposal into the course repository.\\
|
||||
\textbf{Inputs:} The assignment outline, instructor clarification, Victor's
|
||||
project preferences and corrections, current repository sources, and official
|
||||
Prometheus and VictoriaMetrics documentation.\\
|
||||
\textbf{Output used:} Project description, sample task, tentative tool choices,
|
||||
research question, planned comparison, independent SWOT assessments, and
|
||||
supporting document updates.\\
|
||||
\textbf{Human decisions and corrections:} Victor approved the monitoring-service
|
||||
concept, selected VictoriaMetrics instead of InfluxDB, approved the research
|
||||
question, and requested independent SWOT assessments and candidate tools
|
||||
explicitly marked undecided.\\
|
||||
\textbf{Review boundary:} The monitoring prototype, tool comparison, and
|
||||
pipeline remain proposed work. No performance results or completed monitoring
|
||||
features are claimed. The combined report still requires final author review
|
||||
and compilation before submission.
|
||||
@@ -4,9 +4,13 @@
|
||||
\newacronym{mfa}{MFA}{multi-factor authentication}
|
||||
\newacronym{ssh}{SSH}{secure shell}
|
||||
\newacronym{wip}{WIP}{work in progress}
|
||||
\newacronym{wsl}{WSL}{Windows Subsystem for Linux}
|
||||
\newglossaryentry{evidence}{name={evidence},description={A retained record of an
|
||||
actual execution, observation, or review}}
|
||||
\newglossaryentry{host}{name={host},description={A named machine in the
|
||||
development environment, physical or virtual, with an assigned role and owner}}
|
||||
\newglossaryentry{kanban}{name={Kanban board},description={A visual board that
|
||||
represents each unit of work as a card in a column denoting its state}}
|
||||
\newglossaryentry{texlive}{name={TeX Live},description={A cross-platform
|
||||
distribution of the \TeX\ engines, \LaTeX\ packages, fonts, and tools; the
|
||||
distribution Overleaf compiles with}}
|
||||
@@ -0,0 +1,155 @@
|
||||
\chapter{Digital Ocean Docker Deployment}
|
||||
\ChapterLabel{CloudDockerDeployment}
|
||||
\index{Docker}\index{Amazon EC2}\index{JavaScript!classes}
|
||||
|
||||
\section{Scope and Platform}
|
||||
This chapter records Victor's deployment of the group Color Buttons website.
|
||||
The assignment's chapter title is retained; Amazon EC2 replaces the DigitalOcean
|
||||
Droplet in this group's implementation. Payton handles the separate TeX Live
|
||||
compiler and its chapter. UML diagrams are omitted under the instructor's
|
||||
clarification that deployment diagrams are encouraged but optional.
|
||||
|
||||
The website is available at \url{http://54.221.175.174} while the instance is
|
||||
running. This is an HTTP demonstration site without TLS. Its automatically
|
||||
assigned address can change after the instance is stopped and started.
|
||||
|
||||
\section{AWS Configuration}
|
||||
Victor created the paid AWS account for the group and configured a monthly
|
||||
budget alert. No credits were reported. IAM Identity Center provides separate
|
||||
Victor and Payton identities in the developers group, assigned an EC2 permission
|
||||
set using \texttt{AmazonEC2FullAccess}. Root remains the
|
||||
owner's administrative identity; a separate administrator role was not created
|
||||
and MFA setup was deferred. The budget is an alert, not a spending cap.
|
||||
|
||||
\begin{tabularx}{\linewidth}{L{4cm}Y}
|
||||
\toprule \textbf{Setting} & \textbf{Recorded configuration}\\ \midrule
|
||||
Instance name & \texttt{ssw590-group-web}\\
|
||||
Region & N. Virginia (\texttt{us-east-1})\\
|
||||
Instance type & \texttt{t3.micro}\\
|
||||
Operating system & Ubuntu 26.04 LTS, amd64\\
|
||||
Networking & Default VPC, public IPv4 enabled\\
|
||||
Inbound SSH & TCP 22 restricted to Victor's detected IP\\
|
||||
Inbound website & TCP 80 from \texttt{0.0.0.0/0}\\
|
||||
Storage & Launch configuration used an 8 GiB gp3 root volume with encryption and delete-on-termination selected\\
|
||||
Metadata & IMDSv2 required, confirmed in instance summary\\
|
||||
Application port & Container TCP 3000 published as host TCP 80\\
|
||||
\bottomrule
|
||||
\end{tabularx}
|
||||
|
||||
\section{Class-Based Website}
|
||||
The original two click handlers were reorganized into a
|
||||
\texttt{ColorButtonsApp} class. Its constructor retains the background and
|
||||
status elements; \texttt{setColor} changes both; \texttt{connectButton} binds
|
||||
click events; and \texttt{initialize} connects Blue and Red. Express serves the
|
||||
static public directory. Both outcomes were verified locally and on AWS.
|
||||
|
||||
\subsection{Application Sources}
|
||||
\paragraph{Browser class: public/app.js}
|
||||
\inputminted{javascript}{docker/color-buttons/public/app.js}
|
||||
\paragraph{Page: public/index.html}
|
||||
\inputminted{html}{docker/color-buttons/public/index.html}
|
||||
\paragraph{Web server: server.js}
|
||||
\inputminted{javascript}{docker/color-buttons/server.js}
|
||||
\paragraph{Dependencies: package.json}
|
||||
\inputminted{json}{docker/color-buttons/package.json}
|
||||
\paragraph{Dockerfile}
|
||||
\inputminted{docker}{docker/color-buttons/Dockerfile}
|
||||
\paragraph{.dockerignore}
|
||||
\begin{minted}{text}
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.git
|
||||
.DS_Store
|
||||
\end{minted}
|
||||
|
||||
\section{Deployment Procedure}
|
||||
The commands below reproduce the recorded setup and successful configuration.
|
||||
The local folder remained under \path{HW1/HW3/Group-Project} for this assignment;
|
||||
relocating it to the course root is deferred. The private SSH key is stored
|
||||
outside the project and is excluded from the report and repository.
|
||||
|
||||
\subsection{Connect and Install Docker}
|
||||
From Windows Git Bash:
|
||||
\begin{minted}{bash}
|
||||
ssh -i "$HOME/Documents/_SIT/_Fall2026/SSW 590 - DevOps/ssw590-victor.pem" ubuntu@54.221.175.174
|
||||
\end{minted}
|
||||
On the EC2 host:
|
||||
\begin{minted}{bash}
|
||||
cat /etc/os-release
|
||||
uname -m
|
||||
sudo apt update
|
||||
sudo apt install -y ca-certificates curl
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||
sudo chmod 0644 /etc/apt/keyrings/docker.asc
|
||||
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
|
||||
Types: deb
|
||||
URIs: https://download.docker.com/linux/ubuntu
|
||||
Suites: resolute
|
||||
Components: stable
|
||||
Architectures: amd64
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
EOF
|
||||
sudo apt update
|
||||
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
sudo systemctl enable --now docker
|
||||
sudo systemctl is-active docker
|
||||
sudo docker version
|
||||
sudo docker run --rm hello-world
|
||||
\end{minted}
|
||||
Victor reported successful installation after resolving the repository-key error.
|
||||
The procedure follows \url{https://docs.docker.com/engine/install/ubuntu/}.
|
||||
|
||||
\subsection{Transfer, Build, and Run}
|
||||
In a separate local Git Bash terminal, copy the application:
|
||||
\begin{minted}{bash}
|
||||
scp -i "$HOME/Documents/_SIT/_Fall2026/SSW 590 - DevOps/ssw590-victor.pem" -r "$HOME/Documents/_SIT/_Fall2026/SSW 590 - DevOps/HW1/HW3/Group-Project/color-buttons" ubuntu@54.221.175.174:
|
||||
\end{minted}
|
||||
On EC2:
|
||||
\begin{minted}{bash}
|
||||
cd ~/color-buttons
|
||||
sudo docker build -t ssw590-group-buttons .
|
||||
sudo docker run -d --name ssw590-group-buttons --restart unless-stopped -p 80:3000 ssw590-group-buttons
|
||||
sudo docker ps --filter name=ssw590-group-buttons
|
||||
sudo docker logs ssw590-group-buttons
|
||||
curl -I http://127.0.0.1
|
||||
\end{minted}
|
||||
The create command assumes the container name is unused. The restart policy
|
||||
allows the running service to resume after a host restart. The application binds
|
||||
to all container interfaces, and the AWS security group permits public HTTP.
|
||||
|
||||
\section{Verification Evidence}
|
||||
The terminal screenshot shows container \texttt{70ed56f7fae8} running, the
|
||||
\texttt{80->3000/tcp} mapping, the server startup message, and
|
||||
\texttt{HTTP/1.1 200 OK}. Public-browser screenshots record the Blue and Red outcomes.
|
||||
These figures are supplied execution evidence, not generated illustrations.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth]{figures/aws-container.png}
|
||||
\caption{EC2 container status, startup logs, and successful local HTTP check.}
|
||||
\label{fig:aws-container}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[p]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth]{figures/aws-buttons-blue.png}
|
||||
\caption{Public AWS website after clicking Blue.}
|
||||
\label{fig:aws-blue}
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
\includegraphics[width=\linewidth]{figures/aws-buttons-red.png}
|
||||
\caption{Public AWS website after clicking Red.}
|
||||
\label{fig:aws-red}
|
||||
\end{figure}
|
||||
|
||||
\section{Ownership and Continued Operation}
|
||||
Victor owns the AWS account and billing responsibility; both authors share the
|
||||
course project. Compute, storage, and public IPv4 usage are chargeable under
|
||||
this account. The instance is retained for the working assignment link and
|
||||
future labs. Closing SSH does not stop the detached container. Stopping the EC2
|
||||
instance takes the website offline and preserves its disk, which remains
|
||||
billable; restarting can change the public address. No completed shutdown or
|
||||
termination is claimed. Future cleanup and any folder relocation will be
|
||||
recorded separately.
|
||||
@@ -7,11 +7,11 @@
|
||||
\index{Amazon EC2}
|
||||
|
||||
\section{Purpose}
|
||||
This chapter names the hosts that will make up the development environment for
|
||||
\CourseNumber\ and records the role, platform, and ownership of each. It is an
|
||||
inventory of intent: no machine listed here has been provisioned, and the chapter therefore
|
||||
presents no execution \gls{evidence}. It is expected to grow as later
|
||||
assignments add services to the environment.
|
||||
This chapter names the hosts that make up the development environment for
|
||||
\CourseNumber\ and records the role, platform, owner, and status of each.
|
||||
Hosts in service are described here at inventory level; their configuration
|
||||
and execution \gls{evidence} are recorded in the chapter for the activity that
|
||||
uses them. The inventory may grow or change depending on assignment requirements.
|
||||
|
||||
\section{Naming Convention}
|
||||
\index{hosts!naming}
|
||||
@@ -29,55 +29,51 @@ The \textbf{Status} column distinguishes machines already in use from those that
|
||||
will be configured in a later assignment. A host is marked \emph{In service}
|
||||
only once it exists and is reachable.
|
||||
|
||||
\begin{tabularx}{\linewidth}{L{3.0cm}YL{3.3cm}L{2.0cm}}
|
||||
\caption{Planned Host Inventory\label{Table:HostInventory}}\\
|
||||
\begin{tabularx}{\linewidth}{L{3.5cm}YL{3.0cm}L{2.2cm}}
|
||||
\caption{Host Inventory\label{Table:HostInventory}}\\
|
||||
\toprule \textbf{Host name} & \textbf{Role} & \textbf{Platform} & \textbf{Status}\\ \midrule
|
||||
\endfirsthead
|
||||
\multicolumn{4}{l}{\small\itshape Planned Host Inventory (continued)}\\
|
||||
\multicolumn{4}{l}{\small\itshape Host Inventory (continued)}\\
|
||||
\toprule \textbf{Host name} & \textbf{Role} & \textbf{Platform} & \textbf{Status}\\ \midrule
|
||||
\endhead \bottomrule \endlastfoot
|
||||
\texttt{ssw590-group-web} & Group deployment target. Runs the website in \ChapterRef{CloudDockerDeployment}. & Ubuntu 26.04 LTS on Amazon EC2, \texttt{t3.micro} & In service\\
|
||||
\texttt{ssw590-dev-01} & Primary Linux host for the course. Target for service configuration, deployment exercises, and command-line work. & Ubuntu Server LTS on Amazon EC2 & Planned\\
|
||||
\texttt{ssw590-build-01} & Build and integration host, kept separate from the deployment target so that a failed build cannot disturb a running service. To be provisioned only if a later assignment requires it. & Ubuntu Server LTS on Amazon EC2 & Conditional\\
|
||||
\end{tabularx}
|
||||
|
||||
\section{Access and Ownership}
|
||||
\index{hosts!access model}
|
||||
\index{least privilege}
|
||||
All hosts listed above are owned and administered by the author. The following
|
||||
rules govern access to the Linux hosts once they are provisioned.
|
||||
\texttt{ssw590-group-web} is shared by both authors and runs under Victor's AWS account,
|
||||
where each author has a separate IAM identity. The following rules are the target access policy
|
||||
for course Linux hosts:
|
||||
|
||||
\begin{itemize}[leftmargin=*]
|
||||
\item Interactive access is by \gls{ssh} public key only.
|
||||
Password authentication is disabled in the server configuration.
|
||||
The local account password recorded in \ChapterRef{Passwords} authenticates \texttt{sudo} only.
|
||||
\item Inbound \gls{ssh} is restricted by source address to the workstation
|
||||
listed above rather than opened to the public Internet.
|
||||
\item Inbound \gls{ssh} is restricted by source address to the local workstation
|
||||
rather than opened to the public Internet.
|
||||
\item Day-to-day work is performed by an unprivileged account. Administrative
|
||||
rights are granted per command rather than by general membership in the
|
||||
\texttt{sudo} group.
|
||||
\item Should a teammate require access after teams are formalized, that person
|
||||
receives a separate named account rather than a shared login, so that
|
||||
\item Teammates who require access after teams are formalized
|
||||
receive a separate named account rather than a shared login, so that
|
||||
access can be revoked individually and actions remain attributable.
|
||||
\end{itemize}
|
||||
|
||||
\section{Cost and Cleanup}
|
||||
\index{hosts!cost}
|
||||
\index{hosts!teardown}
|
||||
The Linux hosts are expected to run on the smallest instance size that supports
|
||||
the coursework, under whatever free-tier or credit allowance the account
|
||||
provides, with a billing alarm configured before the first instance is
|
||||
launched. Compute is billed per instance-hour, and attached storage whether or
|
||||
not the instance is running, so each additional host adds cost independently of
|
||||
how heavily it is used: provisioning \texttt{ssw590-build-01} alongside
|
||||
\texttt{ssw590-dev-01} would approximately double the compute cost of the
|
||||
environment. It is therefore left unprovisioned until an assignment requires
|
||||
builds to be isolated from the deployment target, and would be stopped between
|
||||
uses rather than run continuously; only \texttt{ssw590-dev-01} needs to remain
|
||||
available at all times.
|
||||
\texttt{ssw590-group-web} runs on a \texttt{t3.micro} instance and is covered
|
||||
by a monthly AWS budget alert. Compute is billed per
|
||||
instance-hour, and attached storage and the public IPv4 address are billed as
|
||||
well, so each additional host adds cost independently of how heavily it is
|
||||
used: provisioning \texttt{ssw590-build-01} would approximately double the
|
||||
compute cost of the environment. It is therefore left unprovisioned unless
|
||||
required in the future, and would be stopped between uses rather than run continuously.
|
||||
|
||||
Each planned host is disposable. Teardown consists of terminating the instance,
|
||||
deleting the attached storage volume, and releasing any static address reserved
|
||||
for it; a static address left reserved after the instance is gone continues to
|
||||
be billed. Because the \gls{ami} and the configuration steps are recorded, a
|
||||
terminated host can be rebuilt rather than preserved, which is why teardown is
|
||||
treated as routine rather than exceptional.
|
||||
Course hosts are disposable. Teardown consists of terminating the instance and
|
||||
deleting its storage volume. \texttt{ssw590-group-web} uses an automatically
|
||||
assigned public address rather than a reserved static address, so there is no
|
||||
address to release; its address changes if the instance is stopped and
|
||||
started.
|
||||
@@ -7,34 +7,29 @@
|
||||
|
||||
\section{Purpose}
|
||||
This document records the configuration of the development environment used for
|
||||
\CourseNumber\ and the working practices followed to produce it. For
|
||||
Assignment~\AssignmentNumber\ it covers three subjects: the \gls{kanban} that
|
||||
plans and tracks the assignment work, the hosts the environment will comprise,
|
||||
and the passwords that will govern accounts on those hosts.
|
||||
|
||||
It is a working record rather than a one-time report. Each subsequent
|
||||
assignment extends it, and the document history records what changed and when,
|
||||
so that the state of the environment at any point in the term can be recovered
|
||||
from this document alone.
|
||||
\CourseNumber\ and the working practices followed to produce it.
|
||||
Each chapter covers one subject, and each assignment adds or revises chapters
|
||||
as recorded in the document history. The latest revision for Assignment~\AssignmentNumber\
|
||||
adds \ChapterRef{CloudDockerDeployment}, \ChapterRef{LatexDocker}, and \ChapterRef{ProjectProposal}.
|
||||
Earlier coursework chapters are retained.
|
||||
|
||||
\section{Scope and Constraints}
|
||||
\index{scope!constraints}
|
||||
The following constraints apply to this revision.
|
||||
|
||||
\begin{itemize}[leftmargin=*]
|
||||
\item The environment is \emph{specified} here, not provisioned. The hosts
|
||||
chapter names the machines to be configured and their intended roles; it
|
||||
does not claim that any host exists, and it therefore presents no
|
||||
execution \gls{evidence}.
|
||||
\item The hosts chapter inventories the hosts in service and those still planned.
|
||||
The cloud deployment chapter records the newly provisioned EC2 website and its actual configuration.
|
||||
\item Linux Commands evidence was recorded locally under WSL. Assignment 3
|
||||
deployment commands were executed on Ubuntu 26.04 on EC2. Supplied screenshots
|
||||
distinguish those environments.
|
||||
\item No credential, access token, private key, or account secret appears in
|
||||
this document. Password rules are documented by derivation hint only, as
|
||||
described in \ChapterRef{Passwords}.
|
||||
\item This is an individual submission. Teams have not yet been formalized, so
|
||||
the board described in \ChapterRef{KanbanSetup} is operated by a single
|
||||
person and every card is assigned to the author.
|
||||
\item This is a group submission. Chapters written before teams were formed
|
||||
were prepared individually and are identified as such in the document history.
|
||||
\item The document is authored in \LaTeX\ and compiled with pdf\LaTeX\ on
|
||||
Overleaf. The board is hosted in GitHub Projects. The planned environment
|
||||
targets Amazon EC2.
|
||||
Overleaf. The board is hosted in GitHub Projects. The group deployment runs on Amazon EC2.
|
||||
\end{itemize}
|
||||
|
||||
\section{Deliverables and Due Date}
|
||||
@@ -42,18 +37,25 @@ The following constraints apply to this revision.
|
||||
\toprule \textbf{Item} & \textbf{Expectation}\\ \midrule
|
||||
Due date & \DueDate\\
|
||||
Instructor & \Instructor\\
|
||||
Team & \Author\\
|
||||
Board & GitHub Projects, \texttt{SSW 590} (private; captured as figures in \ChapterRef{KanbanSetup})\\
|
||||
Required deliverables & Compiled document; Kanban Setup, Passwords, and Hosts chapters; updated document history\\
|
||||
Team policy & Individual submission pending team formalization\\ \bottomrule
|
||||
Required deliverables & Compiled group manual; cloud deployment, LaTeX Docker exercise, tool proposal, and updated history\\
|
||||
Team policy & Group submission\\ \bottomrule
|
||||
\end{tabularx}
|
||||
|
||||
\section{Document Organization}
|
||||
\index{document organization}
|
||||
\ChapterRef{KanbanSetup} describes the tool selected for the board, the steps
|
||||
taken to configure it, the policy governing each column, and the inventory of
|
||||
cards. \ChapterRef{Hosts} names the hosts to be configured and
|
||||
their roles. \ChapterRef{Passwords} defines the account and password rules for those hosts. \ChapterRef{AIPromptLog} records AI assistance used in preparing
|
||||
this document.
|
||||
taken to configure it, the policy governing each column, and the inventory of cards.
|
||||
\ChapterRef{Hosts} inventories the hosts in service and those planned, with their roles.
|
||||
\ChapterRef{Passwords} defines the account and password rules for those hosts.
|
||||
\ChapterRef{LinuxCommands} records the Linux working-directory setup and the problem-set solutions.
|
||||
\ChapterRef{AIPromptLog} records AI assistance used in preparing this document.
|
||||
\ChapterRef{CloudDockerDeployment} records the class-based Color Buttons website,
|
||||
its container, and its deployment to Amazon EC2.
|
||||
\ChapterRef{LatexDocker} records a TeX Live container that compiles \LaTeX\ documents
|
||||
as Overleaf does.
|
||||
\ChapterRef{ProjectProposal} proposes the course project and the DevSecOps tools it will compare.
|
||||
|
||||
This document is derived from the \CourseNumber\ assignment template credited on
|
||||
the Template Attribution page. The template's instructional example chapter and
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
\chapter{LaTeX Docker}
|
||||
\ChapterLabel{LatexDocker}
|
||||
\index{Docker}\index{TeX Live}\index{LaTeX Docker}
|
||||
|
||||
\section{Purpose and Scope}
|
||||
This chapter records a Docker container that compiles a
|
||||
\LaTeX\ document with \gls{texlive}, the distribution Overleaf uses to compile
|
||||
projects.\footnote{\url{https://www.overleaf.com/learn/latex/Overleaf_and_TeX_Live}}
|
||||
Like Overleaf, it drives pdf\LaTeX\ with \texttt{latexmk}, which reruns the
|
||||
engine until cross-references settle.
|
||||
|
||||
The container is a command-line compiler. It reads a
|
||||
\texttt{.tex} file from a mounted folder, writes the PDF back to that folder,
|
||||
and exits. It opens no network ports. The image is not deployed to a course
|
||||
host or published to a registry; it was built and tested locally under WSL on
|
||||
Payton's workstation.
|
||||
|
||||
\section{Design}
|
||||
\begin{tabularx}{\linewidth}{L{3.6cm}Y}
|
||||
\toprule \textbf{Decision} & \textbf{Choice and rationale}\\ \midrule
|
||||
Base image & \texttt{debian:trixie-slim}. Debian packages its TeX Live release, so the image needs no separate TeX Live installer or mirror.\\
|
||||
TeX Live packages & \texttt{texlive-latex-base}, \texttt{texlive-latex-recommended}, \texttt{texlive-fonts-recommended}, and \texttt{lmodern}, installed without recommended extras. This covers common packages such as \texttt{amsmath}, \texttt{hyperref}, and \texttt{booktabs} while avoiding the multi-gigabyte full distribution.\\
|
||||
Build driver & \texttt{latexmk} with pdf\LaTeX, nonstop mode, and halt on the first error, so a failed compile returns a nonzero exit status.\\
|
||||
Interface & The entrypoint is the compiler; the default argument is \texttt{hello.tex}, and any other file name can be passed to \texttt{docker run}.\\
|
||||
Source and output & The document folder is bind-mounted at \path{/work}, so sources are not baked into the image and the PDF is written to the host.\\
|
||||
Privilege & The image defaults to an unprivileged \texttt{latex} user; at run time the container uses the invoking user's IDs so output files are owned by that user. The font cache is kept in \path{/tmp}, outside the mounted folder.\\
|
||||
\bottomrule
|
||||
\end{tabularx}
|
||||
|
||||
\section{Container Sources}
|
||||
|
||||
\paragraph{Dockerfile}
|
||||
\inputminted{docker}{docker/latex-compiler/Dockerfile}
|
||||
\paragraph{.dockerignore}
|
||||
The sample folder is mounted at run time, so it is excluded from the build
|
||||
context.
|
||||
\begin{minted}{text}
|
||||
sample
|
||||
*.pdf
|
||||
\end{minted}
|
||||
\paragraph{Sample document: sample/hello.tex}
|
||||
The document exercises T1 fonts, mathematics, a \texttt{booktabs} table,
|
||||
hyperlinks, and a forward equation reference that resolves only on a second
|
||||
pdf\LaTeX\ pass.
|
||||
\inputminted{latex}{docker/latex-compiler/sample/hello.tex}
|
||||
|
||||
\section{Build and Run}
|
||||
All commands run in a WSL shell from \path{docker/latex-compiler}.
|
||||
|
||||
\subsection{Build the Image}
|
||||
\begin{minted}{bash}
|
||||
docker build -t ssw590-latex .
|
||||
docker image ls ssw590-latex
|
||||
\end{minted}
|
||||
|
||||
\subsection{Compile the Sample Document}
|
||||
\begin{minted}{bash}
|
||||
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD/sample:/work" ssw590-latex
|
||||
ls -l sample/hello.pdf
|
||||
grep "Output written" sample/hello.log
|
||||
\end{minted}
|
||||
\texttt{-{}-rm} deletes the container when compilation ends. \texttt{-{}-user}
|
||||
makes the generated files belong to the WSL user instead of the container
|
||||
user.
|
||||
|
||||
\section{Test Evidence}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth]{figures/latex-docker-build.png}
|
||||
\caption{TeX Live image build under WSL.}
|
||||
\label{fig:latex-docker-build}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth]{figures/latex-docker-output.png}
|
||||
\caption{Information about the produced PDF.}
|
||||
\label{fig:latex-docker-output}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\fbox{\includegraphics[width=0.8\linewidth,page=1]{figures/latex-docker-hello.pdf}}
|
||||
\caption{First page of the PDF produced by the container.}
|
||||
\label{fig:latex-docker-hello}
|
||||
\end{figure}
|
||||
@@ -0,0 +1,579 @@
|
||||
\chapter{Linux Commands}
|
||||
\ChapterLabel{LinuxCommands}
|
||||
\index{Linux}
|
||||
\index{Linux!command line}
|
||||
\index{Linux!working directory}
|
||||
\index{bash}
|
||||
\index{symbolic link}
|
||||
\index{file timestamps}
|
||||
|
||||
\section{Purpose}
|
||||
This chapter records a set of Linux shell commands run in the authors' working
|
||||
user directories, and the solutions to the accompanying problem set.
|
||||
The setup figures reproduce Payton's terminal session. Section~\ref{Section:LinuxEvidence}
|
||||
adds Victor's actual problem-set execution screenshots as \gls{evidence}.
|
||||
The command answers in Section~\ref{Section:LinuxSolutions} describe solutions;
|
||||
where Victor used a different command, the difference is identified rather than
|
||||
presented as an execution of the exact answer shown.
|
||||
|
||||
\section{Environment}
|
||||
\index{Linux!environment}
|
||||
The setup figures were recorded by Payton as user \texttt{payton} on
|
||||
Ubuntu~24.04 under \gls{wsl}, in a \texttt{bash} shell.
|
||||
Victor independently performed the setup and problem set on September 27, 2026,
|
||||
as user \texttt{victor} on host \texttt{Victori7}, running Ubuntu~24.04.3 LTS
|
||||
under WSL~2. His working directory was \texttt{/home/victor/lx-test}.
|
||||
The session was recorded with \texttt{script}; its original transcript is retained
|
||||
with the evidence files. Normal commands ran without elevated privileges;
|
||||
\texttt{sudo} was used for the append-only attribute in Q20.
|
||||
|
||||
\section{Working Directory Setup}
|
||||
\index{Linux!working directory setup}
|
||||
Figure~\ref{Figure:LxTestSetup} shows the executed setup commands in the order given by
|
||||
the assignment. Figure~{\ref{Figure:LxTestDirectories}} shows the resulting directory structure,
|
||||
and Figure~{\ref{Figure:LxTestFiles}} shows the resulting file contents.
|
||||
|
||||
\subsection{What the Commands Do}
|
||||
\index{Linux!command explanations}
|
||||
\begin{sloppypar}
|
||||
\begin{itemize}[leftmargin=*]
|
||||
\item \texttt{mkdir -p \textasciitilde/lx-test \&\& cd \textasciitilde/lx-test}
|
||||
creates the directory, along with any missing parent directories, and does
|
||||
not fail if it already exists. The \texttt{\&\&} operator runs \texttt{cd}
|
||||
only if \texttt{mkdir} succeeds.
|
||||
\item \texttt{printf "\ldots" > \textit{file}} writes the string to a file,
|
||||
turning each \texttt{\textbackslash n} into a newline. The \texttt{>}
|
||||
redirection creates the file or overwrites it if it already exists.
|
||||
\texttt{printf} is used instead of \texttt{echo} for predictable formatting of these strings and newlines, avoiding
|
||||
shell-dependent behavior of \texttt{echo}.
|
||||
\item \texttt{dd} with \texttt{if=/dev/zero}, \texttt{of=blob.bin},
|
||||
\texttt{bs=1K}, and \texttt{count=48} copies $48$ blocks of
|
||||
$1\,\mathrm{KiB}$ from \texttt{/dev/zero}, producing a file of
|
||||
$48 \times 1024 = 49152$ zero bytes.
|
||||
\item \texttt{mkdir -p src/lib tmp archive} creates three directories in one
|
||||
command; \texttt{-p} creates \texttt{src} as the parent of \texttt{lib}.
|
||||
\item \texttt{ln -s src/file1.txt link-to-file1} creates a symbolic link. The
|
||||
stored target is the relative path \texttt{src/file1.txt}, which is
|
||||
resolved relative to the directory that contains the link.
|
||||
\item \texttt{touch -t 202401020304 old.txt} creates \texttt{old.txt} with a
|
||||
modification time of 2024-01-02 03:04 in local time.
|
||||
\item \texttt{ls -lA} lists each named directory in long format, including
|
||||
hidden entries but omitting \texttt{.} and \texttt{..}.
|
||||
\texttt{head} prints the first ten lines of each file under a
|
||||
file name header; every file here is shorter than ten
|
||||
lines, so each is shown in full.
|
||||
\end{itemize}
|
||||
\end{sloppypar}
|
||||
|
||||
\subsection{Interpretation of Results}
|
||||
\index{Linux!result interpretation}
|
||||
Figure~\ref{Figure:LxTestDirectories} confirms each step of the setup:
|
||||
\begin{itemize}[leftmargin=*]
|
||||
\item \textbf{File sizes:} \texttt{blob.bin} is $49152$ bytes, as computed
|
||||
above. Each text file's size equals its characters plus one byte per newline.
|
||||
\item \textbf{Symbolic link:} \texttt{link-to-file1} has type \texttt{l} and
|
||||
points to \texttt{src/file1.txt}.
|
||||
\item \textbf{Timestamp:} \texttt{old.txt} is empty and shows the modified timestamp (\texttt{Jan~2~2024}).
|
||||
\item \textbf{Directories:} \texttt{archive}, \texttt{tmp}, and
|
||||
\texttt{src/lib} show no entries in the \texttt{ls -lA} listing, confirming they are empty
|
||||
(\texttt{total 0} alone would not prove this).
|
||||
\item \textbf{Permissions:} New files are \texttt{rw-r--r--} ($644$) and new
|
||||
directories are \texttt{rwxr-xr-x} ($755$).
|
||||
\end{itemize}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true]
|
||||
payton@paytonpc:~$ mkdir -p ~/lx-test && cd ~/lx-test
|
||||
payton@paytonpc:~/lx-test$ printf "alpha\nbeta\nGamma\ngamma\nbeta\n" > words.txt
|
||||
payton@paytonpc:~/lx-test$ printf "id,name,dept\n1,Ada,EE\n2,Linus,CS\n3,Grace,EE\n4,Dennis,CS\n" > people.csv
|
||||
payton@paytonpc:~/lx-test$ printf "INFO boot ok\nWARN disk low\nERROR fan fail\nINFO shutdown\n" > sys.log
|
||||
payton@paytonpc:~/lx-test$ dd if=/dev/zero of=blob.bin bs=1K count=48 status=none
|
||||
payton@paytonpc:~/lx-test$ mkdir -p src/lib tmp archive
|
||||
payton@paytonpc:~/lx-test$ printf "one two three four\n" > src/file1.txt
|
||||
payton@paytonpc:~/lx-test$ printf "two three four five\n" > src/file2.txt
|
||||
payton@paytonpc:~/lx-test$ ln -s src/file1.txt link-to-file1
|
||||
payton@paytonpc:~/lx-test$ touch -t 202401020304 old.txt
|
||||
\end{lstlisting}
|
||||
\caption{Terminal input for setting up the \texttt{lx-test} working directory.}
|
||||
\label{Figure:LxTestSetup}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true]
|
||||
payton@paytonpc:~/lx-test$ ls -lA . src src/lib archive tmp
|
||||
.:
|
||||
total 72
|
||||
drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 archive
|
||||
-rw-r--r-- 1 payton payton 49152 Sep 26 15:39 blob.bin
|
||||
lrwxrwxrwx 1 payton payton 13 Sep 26 15:39 link-to-file1 -> src/file1.txt
|
||||
-rw-r--r-- 1 payton payton 0 Jan 2 2024 old.txt
|
||||
-rw-r--r-- 1 payton payton 56 Sep 26 15:39 people.csv
|
||||
drwxr-xr-x 3 payton payton 4096 Sep 26 15:39 src
|
||||
-rw-r--r-- 1 payton payton 56 Sep 26 15:39 sys.log
|
||||
drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 tmp
|
||||
-rw-r--r-- 1 payton payton 28 Sep 26 15:39 words.txt
|
||||
|
||||
archive:
|
||||
total 0
|
||||
|
||||
src:
|
||||
total 12
|
||||
-rw-r--r-- 1 payton payton 19 Sep 26 15:39 file1.txt
|
||||
-rw-r--r-- 1 payton payton 20 Sep 26 15:39 file2.txt
|
||||
drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 lib
|
||||
|
||||
src/lib:
|
||||
total 0
|
||||
|
||||
tmp:
|
||||
total 0
|
||||
\end{lstlisting}
|
||||
\caption{Terminal output showing the resulting directories after \texttt{lx-test} setup.}
|
||||
\label{Figure:LxTestDirectories}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true]
|
||||
payton@paytonpc:~/lx-test$ head words.txt people.csv sys.log src/file1.txt src/file2.txt
|
||||
==> words.txt <==
|
||||
alpha
|
||||
beta
|
||||
Gamma
|
||||
gamma
|
||||
beta
|
||||
|
||||
==> people.csv <==
|
||||
id,name,dept
|
||||
1,Ada,EE
|
||||
2,Linus,CS
|
||||
3,Grace,EE
|
||||
4,Dennis,CS
|
||||
|
||||
==> sys.log <==
|
||||
INFO boot ok
|
||||
WARN disk low
|
||||
ERROR fan fail
|
||||
INFO shutdown
|
||||
|
||||
==> src/file1.txt <==
|
||||
one two three four
|
||||
|
||||
==> src/file2.txt <==
|
||||
two three four five
|
||||
\end{lstlisting}
|
||||
\caption{Terminal output showing the resulting file contents after \texttt{lx-test} setup.}
|
||||
\label{Figure:LxTestFiles}
|
||||
\end{figure}
|
||||
|
||||
\clearpage
|
||||
\section{Problem Set Solutions}
|
||||
\label{Section:LinuxSolutions}
|
||||
\index{Linux!problem set}
|
||||
|
||||
\subsection{Navigation and File Operations}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*]
|
||||
\item Show your present working directory path only.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ pwd
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{pwd} prints only the current directory; Victor's result was \texttt{/home/victor/lx-test}.
|
||||
|
||||
\item List all entries in the current directory, one per line, including dotfiles.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ ls -1a
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-1} places each entry on a separate line; \texttt{-a} includes dotfiles and the \texttt{.} and \texttt{..} entries.
|
||||
|
||||
\item Copy \texttt{src/file1.txt} to \texttt{tmp/} only if \texttt{tmp} exists; do it verbosely.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ [ -d tmp ] && cp -v src/file1.txt tmp/
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The directory test prevents copying when \texttt{tmp} is absent; \texttt{-v} reports the source and destination. Victor's output confirms the copy.
|
||||
|
||||
\item Move \texttt{old.txt} into \texttt{archive/} and keep its original timestamp.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ mv old.txt archive/
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Moving within this working tree preserves the file's modification time. Victor verified that the timestamp remained January 2, 2024 at 03:04 local time.
|
||||
|
||||
\item Create a new empty file \texttt{notes.md} only if it doesn't already exist.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ [ -e notes.md ] || touch notes.md
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The existence test avoids touching an existing file. Victor used the equivalent conditional \texttt{if} form and verified that the newly created file was zero bytes.
|
||||
|
||||
\item Show disk usage (human-readable) for the \texttt{src} directory only (not total FS).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ du -sh src
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-s} reports one directory total and \texttt{-h} uses readable units. Victor observed \texttt{16K}; allocated disk usage includes directory storage and is not simply text length.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Viewing and Searching}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Print line numbers while displaying \texttt{sys.log}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ cat -n sys.log
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{cat -n} numbers displayed lines. Victor used \texttt{nl -ba}, which also numbered all four lines in this file.
|
||||
|
||||
\item Show only the lines in \texttt{sys.log} that contain \texttt{ERROR} (case-sensitive).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ grep 'ERROR' sys.log
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Without \texttt{-i}, matching is case-sensitive. The result was \texttt{ERROR fan fail}.
|
||||
|
||||
\item Count how many distinct words appear in \texttt{words.txt} (case-insensitive).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ tr '[:upper:]' '[:lower:]' < words.txt | sort -u | wc -l
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Each input line contains one word. Lowercasing before sorting and deduplication treats \texttt{Gamma} and \texttt{gamma} as one value; the resulting count was three.
|
||||
|
||||
\item From \texttt{words.txt}, show lines that start with \texttt{g} or \texttt{G}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ grep '^[gG]' words.txt
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The anchor \texttt{\^{}} restricts the match to the start of the line, and \texttt{[gG]} accepts either case. The two matches were \texttt{Gamma} and \texttt{gamma}.
|
||||
|
||||
\item Display the first 2 lines of \texttt{people.csv} without using an editor.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ head -n 2 people.csv
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The first two lines are the header and the first data row: \texttt{id,name,dept} and \texttt{1,Ada,EE}.
|
||||
|
||||
\item Show the last 3 lines of \texttt{sys.log} and keep following if the file grows.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ tail -n 3 -f sys.log
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-n 3} selects the last three lines; \texttt{-f} keeps following. Victor captured the initial three lines, then stopped following with Ctrl+C. No later appended-line test is claimed.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Text Processing}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item From \texttt{people.csv}, print only the name column (2nd), excluding the header.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ tail -n +2 people.csv | cut -d, -f2
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{tail} skips the header and \texttt{cut} selects the comma-separated second field. Victor's equivalent \texttt{awk} command returned Ada, Linus, Grace, and Dennis.
|
||||
|
||||
\item Sort \texttt{words.txt} case-insensitively and remove duplicates.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ sort -fu words.txt
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-f} ignores case during comparison and \texttt{-u} removes duplicates. Victor's output was alpha, beta, and Gamma; the retained spelling need not be lowercased.
|
||||
|
||||
\item Replace every \texttt{three} with \texttt{3} in all files under \texttt{src/} in-place, creating \texttt{.bak} backups.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ find src/ -type f ! -name '*.bak' -exec sed -i.bak 's/three/3/g' {} +
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{find} visits regular files recursively, excluding existing backups; \texttt{sed}'s \texttt{g} replaces every occurrence on each line. The original files are saved with the \texttt{.bak} suffix. Victor verified both edited content and original backups. Run once to avoid replacing the original backups on a later run.
|
||||
|
||||
\item Print the number of lines, words, and bytes for every \texttt{*.txt} file in \texttt{src/}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ wc src/*.txt
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
By default, \texttt{wc} reports lines, words, and bytes. After Q15, Victor observed \texttt{1 4 15} and \texttt{1 4 16}, totaling \texttt{2 8 31}. Backup filenames do not match \texttt{*.txt}.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Permissions and Ownership}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Make \texttt{tmp/} readable, writable, and searchable only by the owner.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ chmod 700 tmp/
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Mode \texttt{700} gives the owner read, write, and directory-search permissions, with none for group or others. Victor verified \texttt{drwx------}.
|
||||
|
||||
\item Give group execute permission to \texttt{src/lib} recursively without touching others/owner bits.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ chmod -R g+x src/lib
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{g+x} adds only group execute; \texttt{-R} applies recursively. Victor's before/after value remained \texttt{755} because group execute was already enabled.
|
||||
|
||||
\item Show the numeric (octal) permissions of \texttt{src/file2.txt}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ stat -c '%a' src/file2.txt
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{\%a} requests octal permissions. Victor observed \texttt{644}: owner read/write, group and others read-only.
|
||||
|
||||
\item Make \texttt{notes.md} append-only for the owner via file attributes (if supported).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ chmod 600 notes.md
|
||||
$ sudo chattr +a notes.md
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Mode \texttt{600} limits ordinary access to the owner. The \texttt{a} attribute separately makes the file append-only; it is a file attribute, not an owner-specific permission bit. Victor's filesystem supported it: \texttt{lsattr} showed \texttt{a}, and \texttt{stat} showed \texttt{600}.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Links and Find}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Verify whether \texttt{link-to-file1} is a symlink and show its target path.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ [ -L link-to-file1 ] && readlink link-to-file1
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-L} checks the link itself and \texttt{readlink} prints its stored target. Victor confirmed \texttt{src/file1.txt}.
|
||||
|
||||
\item Find all regular files under the current tree larger than 40~KiB.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ find . -type f -size +40k
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The size test selects regular files larger than 40 KiB. Victor used the equivalent byte threshold \texttt{+40960c}, printing \texttt{./blob.bin} with 49,152 bytes.
|
||||
|
||||
\item Find files modified in the last 10 minutes under \texttt{tmp/} and print their sizes.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ find tmp/ -type f -mmin -10 -printf '%p %s\n'
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-mmin -10} selects recent modifications; \texttt{\%s} prints bytes. Victor's command returned no matches because no regular file under \texttt{tmp/} met that time window.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Processes and Job Control}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Show your processes in a tree view.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ pstree -p "$USER"
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{pstree -p} shows process relationships and PIDs for the specified user. Victor instead recorded his own processes with \texttt{ps -u} and \texttt{--forest}, exposing the shell, recording process, and child shell hierarchy.
|
||||
|
||||
\item Start \texttt{sleep 120} in the background and show its PID.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ sleep 120 & echo $!
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The ampersand starts a background job; \texttt{\$!} is its PID. Victor captured and printed PID 2476 in his session; PIDs vary between executions.
|
||||
|
||||
\item Send a TERM signal to all \texttt{sleep} processes owned by you (don't use \texttt{kill -9}).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ pkill -TERM -u "$USER" -x sleep
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-u} restricts matches to the current user's processes and \texttt{-x} requires the exact name. Victor first checked for unrelated sleep processes, then terminated the test process. Waiting for it returned status 143 (128 + SIGTERM 15), and a final process search returned no matches.
|
||||
|
||||
\item Show the top 5 processes by memory usage (one-shot, not interactive).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ ps aux --sort=-%mem | head -n 6
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Descending memory percentage puts the largest consumers first; six output lines include one header and five processes. Victor used descending resident-memory size (RSS in KiB) instead; his largest displayed process was \texttt{snapd} at 41,208 KiB.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Archiving and Compression}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Create a gzipped tar archive \texttt{src.tgz} from \texttt{src/} with relative paths.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ tar -czf src.tgz src/
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-c} creates, \texttt{-z} compresses with gzip, and \texttt{-f} names the archive. The relative \texttt{src/} operand stores relative member paths.
|
||||
|
||||
\item List the contents of \texttt{src.tgz} without extracting.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ tar -tzf src.tgz
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{-t} lists members without extraction. Victor's archive contained the two text files, their backups, and the \texttt{src/lib/} directory.
|
||||
|
||||
\item Extract only \texttt{file2.txt} from \texttt{src.tgz} into \texttt{tmp/}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ tar -xzvf src.tgz -C tmp/ --strip-components=1 src/file2.txt
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The named member limits extraction to one file, \texttt{-C} selects the destination, and stripping one path component produces \texttt{tmp/file2.txt}. Victor verified matching content with \texttt{cmp}.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Networking and System Information}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Show all listening TCP sockets with associated PIDs (no root assumptions).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ ss -ltnp
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The flags select listening TCP sockets, numeric addresses, and process details when permitted. Victor saw two loopback listeners on port 53; the process column was blank in his unprivileged invocation, so no associated PIDs are claimed.
|
||||
|
||||
\item Print your default route (gateway) in a concise form.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ ip route show default
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Victor's default route used gateway \texttt{172.23.224.1} through \texttt{eth0}. This is a local environment result, not a fixed gateway for every machine.
|
||||
|
||||
\item Display kernel name, release, and machine architecture.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ uname -srm
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The requested fields identify the kernel and architecture. Victor observed Linux, release \texttt{6.18.33.2-microsoft-standard-WSL2}, and \texttt{x86\_64}.
|
||||
|
||||
\item Show the last 5 successful logins (or last sessions) on the system.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ last -n 5
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Victor's last five available records were reboot/system-boot sessions rather than individual user logins. The record type is retained as shown; no successful user authentications are inferred.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Packages and Services (Debian/Ubuntu)}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Show the installed version of package \texttt{coreutils}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ dpkg-query -W -f='${Version}\n' coreutils
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The query reads installed-package metadata. Victor also printed the package name and observed \texttt{coreutils 9.4-3ubuntu6.3}.
|
||||
|
||||
\item Search available packages whose names contain \texttt{ripgrep}.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ apt-cache search --names-only ripgrep
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The search checks package names in the local catalog. It found \texttt{ripgrep}; availability in the catalog does not establish that the package is installed.
|
||||
|
||||
\item Check whether service \texttt{cron} is active and print its status line only.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ systemctl status cron | grep 'Active:'
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
Filtering the detailed status selects its Active line. Victor used \texttt{systemctl is-active cron}, a concise active-state query, and recorded \texttt{active}.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Bash and Scripting}
|
||||
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
|
||||
\item Write a one-liner that loops over \texttt{*.txt} in \texttt{src/} and prints: : .
|
||||
\textbf{Assumption:} the intended output is each file's name and line count, since
|
||||
the supplied problem PDF displays an incomplete output format.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ for f in src/*.txt; do echo "$f: $(wc -l < "$f")"; done
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
For the stated line-count assumption, \texttt{wc -l} counts each file's lines and the loop prefixes its name. Victor's captured command instead printed filename and contents under a different interpretation of the incomplete prompt; Figure~\ref{Figure:HW2-J} documents that alternative.
|
||||
|
||||
\item Write a command that exports CSV rows where \texttt{dept == "CS"} to \texttt{cs.txt} (exclude header).
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ awk -F, 'NR>1 && $3=="CS"' people.csv > cs.txt
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
The field separator is a comma; \texttt{NR>1} skips the header and field three selects CS. Victor verified that \texttt{cs.txt} contained \texttt{2,Linus,CS} and \texttt{4,Dennis,CS}.
|
||||
|
||||
\item Create a variable \texttt{X} with value 42, print it, then remove it from the environment.
|
||||
\begin{lstlisting}[style=cmd]
|
||||
$ export X=42; echo "$X"; unset X
|
||||
\end{lstlisting}
|
||||
\nopagebreak[4]
|
||||
\texttt{export} adds the variable to the shell's exported environment; \texttt{unset} removes it. Victor printed \texttt{X=42}, then verified its absence using \texttt{printenv}.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\section{Problem Set Execution Evidence}
|
||||
\label{Section:LinuxEvidence}
|
||||
These screenshots were supplied by Victor from his recorded September 27th
|
||||
session. They show actual commands and outputs, grouped by problem-set section.
|
||||
They supplement Payton's setup figures. Captions identify the question ranges;
|
||||
the explanations above distinguish equivalent commands.
|
||||
Empty output is retained where it is the observed result.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/03-section-a-q01-q06.png}
|
||||
\caption{Q1--Q6: navigation and file operations. The moved file retains its original modification time, and the new notes file is empty.}
|
||||
\label{Figure:HW2-A}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/04-section-b-q07-q12.png}
|
||||
\caption{Q7--Q12: viewing and searching. The final command remains in follow mode at capture; Victor subsequently stopped it with Ctrl+C.}
|
||||
\label{Figure:HW2-B}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/05-section-c-q13-q16.png}
|
||||
\caption{Q13--Q16: text processing. Original text is retained in the backups, while the edited files total 31 bytes.}
|
||||
\label{Figure:HW2-C}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/06-section-d-q17-q20.png}
|
||||
\caption{Q17--Q20: permissions and attributes. Group execute was already set; the append-only attribute and owner-only notes-file access are verified.}
|
||||
\label{Figure:HW2-D}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/07-section-e-q21-q23.png}
|
||||
\caption{Q21--Q23: links and file searches. The recent-modification search returns no matches.}
|
||||
\label{Figure:HW2-E}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/08-section-f-q24-precheck.png}
|
||||
\caption{Q24 and precheck: Victor records his process tree and confirms no existing user-owned sleep processes before the demonstration.}
|
||||
\label{Figure:HW2-F1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/09-section-f-q25-q27.png}
|
||||
\caption{Q25--Q27: background process, SIGTERM, exit status 143, and the five largest processes by resident-memory usage.}
|
||||
\label{Figure:HW2-F2}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/10-section-g-q28-q30.png}
|
||||
\caption{Q28--Q30: archive creation, member listing, selected extraction, and successful content comparison.}
|
||||
\label{Figure:HW2-G}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/11-section-h-q31-q34.png}
|
||||
\caption{Q31--Q34: sockets, route, kernel, and boot-session history. The unprivileged socket listing contains no process details.}
|
||||
\label{Figure:HW2-H}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/12-section-i-q35-q37.png}
|
||||
\caption{Q35--Q37: installed coreutils version, available ripgrep package, and active cron state.}
|
||||
\label{Figure:HW2-I}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/13-section-j-q38-q40.png}
|
||||
\caption{Q38--Q40: Victor uses the filename-and-contents interpretation for Q38, then verifies the CS export and removal of X from the environment.}
|
||||
\label{Figure:HW2-J}
|
||||
\end{figure}
|
||||
@@ -0,0 +1,111 @@
|
||||
\chapter{Project Proposal}
|
||||
\ChapterLabel{ProjectProposal}
|
||||
\index{Inviscid}\index{Prometheus}\index{VictoriaMetrics}\index{observability}
|
||||
|
||||
\section{Inviscid: Simple Monitoring for Small Web Services}
|
||||
Inviscid is a proposed customer-facing startup that helps small businesses
|
||||
monitor the health and performance of their web applications. Customers would
|
||||
use a dashboard to view availability, response times, request volume, and
|
||||
error rates. The service would pair these measurements with plain-language
|
||||
status summaries, such as ``Your website is responding slowly,'' to help
|
||||
customers recognize problems without requiring extensive monitoring expertise.
|
||||
|
||||
The semester prototype will focus on one demonstration customer application,
|
||||
building on our existing Node.js website. The broader startup concept is a
|
||||
future direction; customer account management and support for multiple
|
||||
customers are outside the initial prototype. Our current proof of concept is
|
||||
the Dockerized Color Buttons website deployed on AWS, documented in
|
||||
\ChapterRef{CloudDockerDeployment}. Monitoring and deployment automation are
|
||||
proposed work rather than completed features.
|
||||
|
||||
\subsection{Sample Customer Task}
|
||||
A customer opens the Inviscid dashboard to check their website's health.
|
||||
During a controlled demonstration, we will generate normal traffic and then
|
||||
introduce slow responses or failed requests in the sample application. The
|
||||
dashboard should display the resulting changes in response times and error
|
||||
rates, accompanied by a short status summary explaining the problem.
|
||||
|
||||
\section{Proposed Development and Operations Tools}
|
||||
GitHub will provide source control and collaboration, and AWS will provide
|
||||
the deployment environment. Table~\ref{Table:InviscidTools} lists the planned
|
||||
stack. Entries marked undecided are candidates, not commitments; the team
|
||||
may revise them as implementation requirements become clearer.
|
||||
|
||||
\begin{tabularx}{\linewidth}{L{3.2cm}Y}
|
||||
\caption{Tentative Inviscid Tool Selection\label{Table:InviscidTools}}\\
|
||||
\toprule \textbf{Purpose} & \textbf{Tool and status}\\ \midrule
|
||||
\endfirsthead
|
||||
\toprule \textbf{Purpose} & \textbf{Tool and status}\\ \midrule
|
||||
\endhead \bottomrule \endlastfoot
|
||||
Source control & GitHub; selected.\\
|
||||
Application & Node.js and Express; proposed, building on the existing website.\\
|
||||
Container packaging & Docker; selected.\\
|
||||
Deployment & AWS EC2; selected for the prototype.\\
|
||||
Metrics backend & Prometheus and single-node VictoriaMetrics; selected for comparison, final backend undecided.\\
|
||||
Dashboard & Grafana or a simple custom dashboard; undecided.\\
|
||||
Automated testing & Node.js's built-in test runner and a traffic-generation script; undecided.\\
|
||||
Deployment automation & GitHub Actions for a manually triggered build, test, and deployment workflow; undecided.\\
|
||||
Customer/settings database & Amazon DynamoDB, if persistent customer configuration is needed; undecided. Metrics will be stored in the selected metrics backend.\\
|
||||
Security checks & GitHub Dependabot and automated dependency checks; undecided.\\
|
||||
\end{tabularx}
|
||||
|
||||
Our longer-term goal is a deployment pipeline that can be initiated with one
|
||||
button press. The proposal does not claim that this pipeline is implemented.
|
||||
|
||||
\section{Research Question and Planned Comparison}
|
||||
\begin{quote}
|
||||
How do Prometheus and VictoriaMetrics compare as metrics backends for
|
||||
Inviscid's prototype in terms of configuration effort, dashboard integration,
|
||||
query response time, and CPU, memory, and storage usage?
|
||||
\end{quote}
|
||||
|
||||
We selected these tools because both can collect and query application metrics,
|
||||
and VictoriaMetrics can scrape Prometheus-compatible endpoints. This allows
|
||||
us to reuse the instrumented application while investigating different
|
||||
backend implementations. Prometheus includes metric scraping, PromQL queries,
|
||||
and alert-rule evaluation. VictoriaMetrics provides metric collection and
|
||||
storage with MetricsQL queries; alert-rule evaluation uses a separate component
|
||||
such as \texttt{vmalert}. Supported configuration options and query behavior
|
||||
will be checked rather than assumed identical.
|
||||
|
||||
We plan to compare Prometheus with single-node VictoriaMetrics using the same
|
||||
application, metrics, traffic workload, collection interval, retention period,
|
||||
and equivalent AWS resources. Configuration effort will be documented through
|
||||
setup steps and difficulties; dashboard integration through the work required
|
||||
to display equivalent measurements. Repeated equivalent queries and controlled
|
||||
traffic will support measurements of query response time and CPU, memory,
|
||||
and storage usage. Results will apply to the tested prototype and workload;
|
||||
we will not assume that either tool is faster or more resource-efficient.
|
||||
|
||||
\section{Preliminary SWOT Analysis}
|
||||
Table~\ref{Table:InviscidSWOT} evaluates each tool independently in the context
|
||||
of Inviscid. Strengths and weaknesses describe tool characteristics;
|
||||
opportunities and threats describe possible circumstances affecting its use.
|
||||
These are preliminary assessments, not measured experimental results.
|
||||
|
||||
\begingroup
|
||||
\small
|
||||
\begin{tabularx}{\linewidth}{L{2.2cm}YY}
|
||||
\caption{Preliminary SWOT for Inviscid's Metrics Backends\label{Table:InviscidSWOT}}\\
|
||||
\toprule \textbf{Category} & \textbf{Prometheus} & \textbf{VictoriaMetrics}\\ \midrule
|
||||
\endfirsthead
|
||||
\multicolumn{3}{l}{\small\itshape Preliminary SWOT (continued)}\\
|
||||
\toprule \textbf{Category} & \textbf{Prometheus} & \textbf{VictoriaMetrics}\\ \midrule
|
||||
\endhead \bottomrule \endlastfoot
|
||||
Strengths & Established open-source ecosystem; built-in metric collection and alert-rule evaluation; expressive PromQL query language. & Simple single-node deployment; built-in metric collection and storage; flexible MetricsQL query language and multiple supported ingestion formats.\\
|
||||
Weaknesses & Local storage is neither clustered nor replicated; operating at larger scales requires additional architecture. & Alert-rule evaluation requires a separate component; the single-node deployment depends on one server for availability.\\
|
||||
Opportunities & Inviscid could extend monitoring to containers and infrastructure through its existing exporter ecosystem. & Inviscid could accept metrics from different customer environments through its supported ingestion formats.\\
|
||||
Threats & Rapid growth in customer metrics could exceed available resources and increase operating costs. & Customers requiring uninterrupted monitoring could necessitate a cluster deployment, increasing infrastructure and maintenance costs.\\
|
||||
\end{tabularx}
|
||||
\endgroup
|
||||
|
||||
\section{Technical Sources}
|
||||
The technical characteristics above are based on the following official
|
||||
documentation, consulted October 6, 2026. Opportunities and threats are the
|
||||
team's project-specific assessments. Specific tool versions will be recorded
|
||||
when the comparison is implemented.
|
||||
\begin{itemize}
|
||||
\item \href{https://prometheus.io/docs/introduction/overview/}{Prometheus overview}: collection, queries, exporters, and alerting components.
|
||||
\item \href{https://prometheus.io/docs/prometheus/latest/storage/}{Prometheus storage}: local storage limitations and remote storage interfaces.
|
||||
\item \href{https://docs.victoriametrics.com/victoriametrics/}{VictoriaMetrics documentation}: single-node deployment, scraping, ingestion, MetricsQL, and supporting components.
|
||||
\end{itemize}
|
||||
@@ -8,6 +8,7 @@
|
||||
\usepackage{xspace}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{pdflscape} % Full-page terminal evidence
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{amsmath,amssymb}
|
||||
\usepackage{array}
|
||||
@@ -15,9 +16,12 @@
|
||||
\usepackage{longtable}
|
||||
\usepackage{tabularx}
|
||||
\usepackage{ltablex}
|
||||
\usepackage{float}
|
||||
\keepXColumns
|
||||
\usepackage{enumitem}
|
||||
\usepackage{listings}
|
||||
\usepackage{minted}
|
||||
\setminted{fontsize=\footnotesize,breaklines,frame=single}
|
||||
\usepackage{tcolorbox}
|
||||
\usepackage{makeidx}
|
||||
\usepackage[colorlinks=true,citecolor=blue,linkcolor=blue,urlcolor=blue]{hyperref}
|
||||
@@ -34,17 +38,17 @@
|
||||
\definecolor{devopsLightBlue}{RGB}{232,240,247}
|
||||
|
||||
% Replace these values for each assignment.
|
||||
\newcommand{\AssignmentTitle}{Compile Overleaf Document and Detail Kanban Setup}
|
||||
\newcommand{\AssignmentNumber}{1}
|
||||
\newcommand{\DocumentVersion}{1.0}
|
||||
\newcommand{\AssignmentTitle}{Cloud Docker Deployment, LaTeX Docker, and Project Proposal}
|
||||
\newcommand{\AssignmentNumber}{3}
|
||||
\newcommand{\DocumentVersion}{3.2}
|
||||
\newcommand{\DocumentStatus}{Submitted Document}
|
||||
\newcommand{\CourseNumber}{SSW 590}
|
||||
\newcommand{\CourseName}{DevOps}
|
||||
\newcommand{\Author}{Payton Bates}
|
||||
\newcommand{\Author}{Payton Bates and Victor Del Rio Foces}
|
||||
\newcommand{\Instructor}{Darian Muresan, Ph.D.}
|
||||
\newcommand{\Organization}{Stevens Institute of Technology}
|
||||
\newcommand{\DocumentDate}{September 18, 2026}
|
||||
\newcommand{\DueDate}{September 21, 2026 by 11:59pm}
|
||||
\newcommand{\DocumentDate}{October 6, 2026}
|
||||
\newcommand{\DueDate}{October 6, 2026 by 11:59pm}
|
||||
\newcommand{\VERSION}{Version \DocumentVersion}
|
||||
|
||||
\hypersetup{
|
||||
@@ -52,12 +56,14 @@
|
||||
pdfauthor={\Author},
|
||||
pdfcreator={Darian Muresan, Ph.D., with OpenAI Codex and Anthropic Claude Code},
|
||||
pdfsubject={Development environment configuration record for \CourseNumber\ Assignment \AssignmentNumber\ },
|
||||
pdfkeywords={DevOps, Kanban, password, host, development environment, Amazon EC2, GitHub Projects}
|
||||
pdfkeywords={DevOps, Kanban, password, host, development environment, Amazon EC2, GitHub Projects, Docker, TeX Live}
|
||||
}
|
||||
|
||||
\newcolumntype{Y}{>{\raggedright\arraybackslash}X}
|
||||
\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}}
|
||||
\setlength{\tabcolsep}{4pt}
|
||||
\setlength{\headheight}{16pt}
|
||||
\setlength{\emergencystretch}{2em}
|
||||
\renewcommand{\arraystretch}{1.12}
|
||||
\setlength{\LTpre}{6pt}
|
||||
\setlength{\LTpost}{6pt}
|
||||
@@ -88,6 +94,8 @@
|
||||
stringstyle=\color{devopsRed}, tabsize=2
|
||||
}
|
||||
|
||||
\lstdefinestyle{cmd}{numbers=none, columns=fullflexible, upquote=true, belowskip=0pt, xleftmargin=5pt, xrightmargin=0pt}
|
||||
|
||||
\changenormalspacing{\singlespacing}
|
||||
\begin{document}
|
||||
\pagenumbering{roman}
|
||||
@@ -112,6 +120,10 @@
|
||||
\include{chapters/devopsKanbanSetup}
|
||||
\include{chapters/devopsHosts}
|
||||
\include{chapters/devopsPasswords}
|
||||
\include{chapters/devopsLinuxCommands}
|
||||
\include{chapters/devopsCloudDockerDeployment}
|
||||
\include{chapters/devopsLatexDocker}
|
||||
\include{chapters/devopsProjectProposal}
|
||||
|
||||
\appendix
|
||||
\include{backmatter/devopsAIPromptLog}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.git
|
||||
.DS_Store
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install --omit=dev
|
||||
|
||||
COPY server.js ./
|
||||
COPY public ./public
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["npm", "start"]
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "ssw590-group-buttons",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
class ColorButtonsApp {
|
||||
constructor(backgroundElement, statusElement) {
|
||||
this.backgroundElement = backgroundElement;
|
||||
this.statusElement = statusElement;
|
||||
}
|
||||
|
||||
setColor(color) {
|
||||
this.backgroundElement.style.backgroundColor = color;
|
||||
this.statusElement.textContent = `Current background: ${color}`;
|
||||
}
|
||||
|
||||
connectButton(button, color) {
|
||||
button.addEventListener("click", () => this.setColor(color));
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.connectButton(document.getElementById("blueBtn"), "blue");
|
||||
this.connectButton(document.getElementById("redBtn"), "red");
|
||||
}
|
||||
}
|
||||
|
||||
const application = new ColorButtonsApp(
|
||||
document.body,
|
||||
document.getElementById("status"),
|
||||
);
|
||||
|
||||
application.initialize();
|
||||
@@ -0,0 +1,43 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>SSW590 Group — Color Buttons</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background-color: white;
|
||||
font-family: Arial, sans-serif;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
main {
|
||||
max-width: 600px;
|
||||
margin: 50px auto;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
margin: 10px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<script src="app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Color Buttons</h1>
|
||||
<p>Victor Del Rio Foces and Payton Bates — SSW590</p>
|
||||
<button id="blueBtn" type="button">Blue</button>
|
||||
<button id="redBtn" type="button">Red</button>
|
||||
<p id="status" aria-live="polite">Current background: white</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
import express from "express";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const directory = path.dirname(fileURLToPath(import.meta.url));
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
app.use(express.static(path.join(directory, "public")));
|
||||
|
||||
app.listen(port, "0.0.0.0", () => {
|
||||
console.log(`Group buttons website listening on port ${port}`);
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
# Inviscid Gitea foundation
|
||||
|
||||
This is the temporary, Gitea-only deployment while Student Pack registration is pending.
|
||||
The official image version is pinned; verify that it pulls before starting the service.
|
||||
SQLite is `/data/gitea/gitea.db`; repositories and other application data share the
|
||||
persistent named volume `inviscid_gitea_data`. Container replacement must preserve it.
|
||||
Never run `docker compose down --volumes` against the working service.
|
||||
|
||||
Only EC2 loopback port 3000 is published. Initial browser access uses an SSH tunnel.
|
||||
The existing Color Buttons container remains unchanged on port 80.
|
||||
No public backend or Git SSH firewall rule is needed.
|
||||
|
||||
From this directory on EC2:
|
||||
|
||||
```sh
|
||||
sudo docker compose config --quiet
|
||||
sudo docker compose pull
|
||||
sudo docker compose up -d
|
||||
sudo docker compose ps
|
||||
```
|
||||
|
||||
This initial configuration is NOT the final hostname-based HTTPS deployment.
|
||||
After domain registration, replace DOMAIN and ROOT_URL with the actual hostname
|
||||
and HTTPS URL. Payton can attach Caddy to `inviscid_services` and forward to
|
||||
`gitea:3000`, publish the proxy web ports, persist certificate state, and resolve
|
||||
the existing website's port-80 mapping. Remove the loopback mapping if no longer needed.
|
||||
|
||||
Self-registration is disabled. Create the initial administrator through the installer;
|
||||
create Payton's separate account using administration after initialization.
|
||||
Keep passwords, app.ini, database files, and volume contents out of Git and screenshots.
|
||||
|
||||
Sources:
|
||||
- https://docs.gitea.com/installation/install-with-docker/
|
||||
- https://docs.gitea.com/administration/config-cheat-sheet/
|
||||
|
||||
## Recorded deployment (October 12, 2026)
|
||||
|
||||
- EC2: `ssw590-group-web`, `i-025a57432604c8d4b`, us-east-1.
|
||||
- Current public Elastic IP: `100.49.80.94` (replaces `54.221.175.174`).
|
||||
- Remote configuration directory: `/home/ubuntu/gitea`.
|
||||
- Observed image digest: `docker.gitea.com/gitea@sha256:f505a0d3a41323b786e05942fc7a4075e07ae7c169fd9485649aa55ee543a21a`.
|
||||
- Gitea initialized with site title Inviscid; victor is administrator and payton is a regular user.
|
||||
- Local HTTP check returned 200; named-volume mount and SQLite file were verified.
|
||||
- Both containers remained running following Elastic IP association.
|
||||
- Domain registration, public HTTPS, renewal verification, external firewall checks,
|
||||
container-replacement persistence test, and team PR workflow remain incomplete.
|
||||
|
||||
For private browser access, use your own authorized key:
|
||||
|
||||
```sh
|
||||
ssh -i /path/to/your-private-key -o ExitOnForwardFailure=yes -N -L 127.0.0.1:3000:127.0.0.1:3000 ubuntu@100.49.80.94
|
||||
```
|
||||
|
||||
Open http://localhost:3000 while the tunnel stays open. Each team member must
|
||||
have their public key authorized and their source IP allowed for administrative SSH.
|
||||
@@ -0,0 +1,31 @@
|
||||
name: inviscid
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: docker.gitea.com/gitea:28.1.0
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
USER_UID: "1000"
|
||||
USER_GID: "1000"
|
||||
GITEA__database__DB_TYPE: sqlite3
|
||||
GITEA__database__PATH: /data/gitea/gitea.db
|
||||
# Temporary URLs for SSH-tunnel initialization; replace after registration.
|
||||
GITEA__server__DOMAIN: localhost
|
||||
GITEA__server__ROOT_URL: http://localhost:3000/
|
||||
GITEA__server__HTTP_PORT: "3000"
|
||||
GITEA__server__DISABLE_SSH: "true"
|
||||
GITEA__service__DISABLE_REGISTRATION: "true"
|
||||
ports:
|
||||
- "127.0.0.1:3000:3000"
|
||||
volumes:
|
||||
- gitea_data:/data
|
||||
networks:
|
||||
- services
|
||||
|
||||
volumes:
|
||||
gitea_data:
|
||||
name: inviscid_gitea_data
|
||||
|
||||
networks:
|
||||
services:
|
||||
name: inviscid_services
|
||||
@@ -0,0 +1,2 @@
|
||||
sample
|
||||
*.pdf
|
||||
@@ -0,0 +1,20 @@
|
||||
FROM debian:trixie-slim
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
texlive-latex-base \
|
||||
texlive-latex-recommended \
|
||||
texlive-fonts-recommended \
|
||||
lmodern \
|
||||
latexmk \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Run as an unprivileged user; keep TeX's font cache out of the mounted folder.
|
||||
RUN useradd --create-home --uid 1000 latex
|
||||
ENV TEXMFVAR=/tmp/texmf-var
|
||||
USER latex
|
||||
WORKDIR /work
|
||||
|
||||
ENTRYPOINT ["latexmk", "-pdf", "-interaction=nonstopmode", "-halt-on-error"]
|
||||
CMD ["hello.tex"]
|
||||
@@ -0,0 +1,44 @@
|
||||
\documentclass[11pt]{article}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{lmodern}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{booktabs}
|
||||
\usepackage[colorlinks=true]{hyperref}
|
||||
|
||||
\title{SSW 590 --- LaTeX Docker Test}
|
||||
\author{Payton Bates and Victor Del Rio Foces}
|
||||
\date{\today}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section{Purpose}
|
||||
This document was compiled by pdf\LaTeX\ from TeX Live inside a Docker
|
||||
container. Section~\ref{sec:checks} lists its features.
|
||||
|
||||
\section{Checks}\label{sec:checks}
|
||||
\begin{itemize}
|
||||
\item Mathematics: $e^{i\pi} + 1 = 0$ and
|
||||
\begin{equation}
|
||||
\sum_{k=1}^{n} k = \frac{n(n+1)}{2}.
|
||||
\end{equation}
|
||||
\item Cross-reference: Equation~\eqref{eq:area} resolves.
|
||||
\item Table:
|
||||
\end{itemize}
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{lr}
|
||||
\toprule
|
||||
Item & Value \\
|
||||
\midrule
|
||||
Engine & pdf\LaTeX \\
|
||||
Distribution & TeX Live \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\begin{equation}\label{eq:area}
|
||||
A = \pi r^2
|
||||
\end{equation}
|
||||
|
||||
\end{document}
|
||||
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 245 KiB |
|
After Width: | Height: | Size: 772 KiB |
|
After Width: | Height: | Size: 39 KiB |
@@ -1,7 +1,11 @@
|
||||
This document records the development-environment configuration for the first
|
||||
SSW 590 assignment. It describes the Kanban board used to plan and track the
|
||||
work, the hosts the environment will comprise, and the password rules that
|
||||
will govern accounts on those hosts. The environment is specified here as a
|
||||
plan; provisioning and its supporting evidence are deferred to a later
|
||||
submission. Password rules are recorded as derivation hints, so that no
|
||||
credential appears in this document.
|
||||
This document records the development environment and working practices used
|
||||
in SSW 590. It is extended with each assignment, and the document history
|
||||
identifies what each revision changed. Its chapters currently cover planning and tracking
|
||||
the work, the hosts and accounts that make up the environment, and the
|
||||
command-line and operational work performed in it. The host inventory
|
||||
distinguishes machines in service from those still planned.
|
||||
Assignment 3 adds the class-based Color Buttons application deployed in Docker
|
||||
on Amazon EC2, with public browser and terminal verification evidence;
|
||||
a Docker container that compiles \LaTeX\ documents as Overleaf does;
|
||||
and the Inviscid monitoring-service proposal, including a planned comparison
|
||||
of Prometheus and VictoriaMetrics.
|
||||
@@ -11,5 +11,10 @@ link each entry to the changed chapter, table, figure, or controlled artifact.
|
||||
\multicolumn{4}{l}{\small\itshape Document Update History (continued)}\\
|
||||
\toprule \textbf{Date / Version} & \textbf{Author Initials} & \textbf{Change} & \textbf{Changed At}\\ \midrule
|
||||
\endhead \bottomrule \endlastfoot
|
||||
October 6, 2026 / 3.2 & VDRF & Replaced the preliminary tool proposal with Inviscid, its sample customer task, tentative stack, research question, and independent SWOT assessments of Prometheus and VictoriaMetrics. Updated the abstract and AI log. & \ChapterRef{ProjectProposal}, \ChapterRef{AIPromptLog}\\
|
||||
October 5, 2026 / 3.1 & PCB & Added the LaTeX Docker chapter for compiling a sample document with its sources, build and run commands, and test evidence. Updated the document title, keywords, glossary, abstract, introduction, and hosts. & \ChapterRef{LatexDocker}, \ChapterRef{Hosts}, \ChapterRef{Introduction}, \ChapterRef{CloudDockerDeployment}\\
|
||||
October 5, 2026 / 3.0 & VDRF & Added AWS Docker deployment, class-based website sources, execution evidence, and a draft tool-comparison proposal. Updated Assignment 3 metadata and AI log. & \ChapterRef{CloudDockerDeployment}, \ChapterRef{ProjectProposal}, \ChapterRef{AIPromptLog}\\
|
||||
September 27, 2026 / 2.1 & VDRF & Added Victor's Q1--Q40 execution screenshots and result interpretation; distinguished the two environments and command variants. & \ChapterRef{LinuxCommands}, \ChapterRef{AIPromptLog}\\
|
||||
September 26, 2026 / 2.0 & PCB, VDRF & Added the Linux Commands chapter: working-directory setup with terminal input/output figures, command explanations and interpretation of results, and solutions to the Linux problem set. Updated document metadata and authorship for Assignment 2 and the two-person team. & \ChapterRef{LinuxCommands}, \ChapterRef{Introduction}, \ChapterRef{Hosts}, \ChapterRef{AIPromptLog}\\
|
||||
September 18, 2026 / 1.0 & PCB & Created this document from the \CourseNumber\ assignment template. Removed instructional/example chapters, set document metadata and authorship, and rewrote the abstract and introduction to describe this environment rather than the template. Added the Kanban Setup, Passwords, and Hosts chapters, the account and password rules, and the planned hosts. & \ChapterRef{Introduction}, \ChapterRef{KanbanSetup}, \ChapterRef{Passwords}, \ChapterRef{Hosts}, \ChapterRef{AIPromptLog}\\
|
||||
\end{tabularx}
|
||||
@@ -0,0 +1,17 @@
|
||||
# Allow minted to call its external highlighter (Overleaf enables this by default).
|
||||
$pdflatex = 'pdflatex -shell-escape %O %S';
|
||||
|
||||
# Run makeglossaries whenever the glossary/acronym input files change.
|
||||
# Overleaf does this automatically; local latexmk (e.g. VS Code LaTeX Workshop) does not.
|
||||
add_cus_dep('glo', 'gls', 0, 'run_makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'run_makeglossaries');
|
||||
|
||||
sub run_makeglossaries {
|
||||
my ($base_name, $path) = fileparse($_[0]);
|
||||
my @args = ('-d', $path, $base_name);
|
||||
unshift @args, '-q' if $silent;
|
||||
return system('makeglossaries', @args);
|
||||
}
|
||||
|
||||
push @generated_exts, 'glo', 'gls', 'glg', 'acn', 'acr', 'alg';
|
||||
$clean_ext .= ' %R.ist %R.xdy';
|
||||