2103 lines
81 KiB
HTML
2103 lines
81 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>ArgoBox | Ansible Sandbox</title>
|
|
|
|
<!-- SEO Meta Tags -->
|
|
<meta name="description" content="Interactive Ansible playbook testing environment. Deploy test configurations and see infrastructure automation in action.">
|
|
|
|
<!-- Favicon -->
|
|
<link rel="icon" href="images/favicon.ico" type="image/x-icon">
|
|
|
|
<!-- CSS -->
|
|
<link rel="stylesheet" href="styles.css">
|
|
|
|
<!-- Google Fonts -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
|
|
<!-- Font Awesome -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
|
|
|
<style>
|
|
:root {
|
|
/* Main Colors */
|
|
--primary-bg: #0f172a;
|
|
--secondary-bg: #1e293b;
|
|
--accent: #3b82f6;
|
|
--accent-darker: #2563eb;
|
|
--accent-gradient: linear-gradient(135deg, #2563eb, #3b82f6);
|
|
--accent-red: #ef4444;
|
|
--accent-green: #10b981;
|
|
--accent-yellow: #f59e0b;
|
|
--accent-glow: 0 0 15px rgba(59, 130, 246, 0.5);
|
|
|
|
/* Text Colors */
|
|
--text-primary: #e2e8f0;
|
|
--text-secondary: #94a3b8;
|
|
--text-accent: #3b82f6;
|
|
|
|
/* Status Colors */
|
|
--success: #10b981;
|
|
--warning: #f59e0b;
|
|
--error: #ef4444;
|
|
--info: #0ea5e9;
|
|
|
|
/* UI Elements */
|
|
--border: rgba(71, 85, 105, 0.5);
|
|
--card-bg: rgba(30, 41, 59, 0.8);
|
|
--card-hover-bg: rgba(30, 41, 59, 0.95);
|
|
--card-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
|
|
--glass-effect: saturate(180%) blur(10px);
|
|
|
|
/* Animation Timing */
|
|
--transition-fast: 0.2s ease;
|
|
--transition-normal: 0.3s ease;
|
|
--transition-slow: 0.5s ease;
|
|
}
|
|
|
|
/* Reset & Base Styles */
|
|
*, *::before, *::after {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
background-color: var(--primary-bg);
|
|
color: var(--text-primary);
|
|
line-height: 1.6;
|
|
overflow-x: hidden;
|
|
min-height: 100vh;
|
|
background-image:
|
|
radial-gradient(circle at 20% 35%, rgba(29, 78, 216, 0.15) 0%, transparent 50%),
|
|
radial-gradient(circle at 75% 60%, rgba(14, 165, 233, 0.1) 0%, transparent 50%);
|
|
}
|
|
|
|
.container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 0 1.5rem;
|
|
}
|
|
|
|
/* Sandbox Specific Styles */
|
|
.sandbox-container {
|
|
padding: 6rem 0 2rem;
|
|
}
|
|
|
|
.sandbox-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.sandbox-title {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.sandbox-title h1 {
|
|
font-size: 1.75rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.sandbox-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.sandbox-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 0.5rem;
|
|
background-color: var(--card-bg);
|
|
border: 1px solid var(--border);
|
|
color: var(--text-primary);
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all var(--transition-normal);
|
|
}
|
|
|
|
.sandbox-btn:hover {
|
|
background-color: var(--card-hover-bg);
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
.sandbox-btn i {
|
|
color: var(--accent);
|
|
}
|
|
|
|
.btn-primary {
|
|
background: var(--accent-gradient);
|
|
color: white;
|
|
border: none;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
box-shadow: var(--accent-glow);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.sandbox-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 2fr;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.playbook-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
padding-right: 0.5rem;
|
|
scrollbar-width: thin;
|
|
scrollbar-color: var(--border) transparent;
|
|
}
|
|
|
|
.playbook-list::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.playbook-list::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
|
|
.playbook-list::-webkit-scrollbar-thumb {
|
|
background-color: var(--border);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.playbook-card {
|
|
background-color: var(--card-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.75rem;
|
|
padding: 1.25rem;
|
|
cursor: pointer;
|
|
transition: all var(--transition-normal);
|
|
}
|
|
|
|
.playbook-card:hover {
|
|
transform: translateY(-3px);
|
|
border-color: var(--accent);
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.playbook-card.active {
|
|
border-color: var(--accent);
|
|
background-color: rgba(59, 130, 246, 0.1);
|
|
}
|
|
|
|
.playbook-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.playbook-title {
|
|
font-weight: 600;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.playbook-tag {
|
|
font-size: 0.75rem;
|
|
padding: 0.15rem 0.5rem;
|
|
border-radius: 9999px;
|
|
background-color: rgba(59, 130, 246, 0.1);
|
|
color: var(--accent);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.playbook-description {
|
|
font-size: 0.9rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.playbook-details {
|
|
display: flex;
|
|
gap: 1rem;
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.playbook-detail {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
}
|
|
|
|
.playbook-detail i {
|
|
font-size: 0.85rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.sandbox-preview {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 80vh;
|
|
}
|
|
|
|
.preview-container {
|
|
background-color: var(--card-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.75rem;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.preview-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.preview-title {
|
|
font-weight: 600;
|
|
font-size: 1.1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.preview-tabs {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.preview-tab {
|
|
color: var(--text-secondary);
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
padding-bottom: 0.25rem;
|
|
border-bottom: 2px solid transparent;
|
|
transition: all var(--transition-normal);
|
|
}
|
|
|
|
.preview-tab:hover {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.preview-tab.active {
|
|
color: var(--accent);
|
|
border-bottom-color: var(--accent);
|
|
}
|
|
|
|
.preview-content {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.tab-content {
|
|
display: none;
|
|
flex: 1;
|
|
overflow: auto;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.tab-content.active {
|
|
display: block;
|
|
}
|
|
|
|
.code-editor {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 0.9rem;
|
|
line-height: 1.5;
|
|
overflow: auto;
|
|
height: 100%;
|
|
}
|
|
|
|
.code-line {
|
|
display: flex;
|
|
}
|
|
|
|
.line-number {
|
|
width: 3rem;
|
|
text-align: right;
|
|
padding-right: 1rem;
|
|
user-select: none;
|
|
color: var(--text-secondary);
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.line-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.code-comment {
|
|
color: #6b7280;
|
|
font-style: italic;
|
|
}
|
|
|
|
.code-key {
|
|
color: #93c5fd;
|
|
}
|
|
|
|
.code-value {
|
|
color: #fbbf24;
|
|
}
|
|
|
|
.code-string {
|
|
color: #a3be8c;
|
|
}
|
|
|
|
.preview-form {
|
|
padding: 1.5rem;
|
|
overflow: auto;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.form-label {
|
|
display: block;
|
|
margin-bottom: 0.5rem;
|
|
font-weight: 500;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.form-control {
|
|
width: 100%;
|
|
padding: 0.75rem 1rem;
|
|
background-color: var(--primary-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.5rem;
|
|
color: var(--text-primary);
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 0.9rem;
|
|
transition: all var(--transition-normal);
|
|
}
|
|
|
|
.form-control:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
|
|
}
|
|
|
|
.form-select {
|
|
appearance: none;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2394a3b8'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right 1rem center;
|
|
background-size: 1em;
|
|
}
|
|
|
|
.form-text {
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.form-check {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.form-check-input {
|
|
margin-right: 0.75rem;
|
|
appearance: none;
|
|
width: 1.25rem;
|
|
height: 1.25rem;
|
|
background-color: var(--primary-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.25rem;
|
|
cursor: pointer;
|
|
transition: all var(--transition-normal);
|
|
position: relative;
|
|
}
|
|
|
|
.form-check-input:checked {
|
|
background-color: var(--accent);
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
.form-check-input:checked::after {
|
|
content: '✓';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
color: white;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.form-check-label {
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.terminal {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 0.85rem;
|
|
line-height: 1.5;
|
|
padding: 1.5rem;
|
|
background-color: #1a1a1a;
|
|
color: #e2e8f0;
|
|
overflow: auto;
|
|
height: 100%;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.terminal-line {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.terminal-success {
|
|
color: var(--success);
|
|
}
|
|
|
|
.terminal-error {
|
|
color: var(--error);
|
|
}
|
|
|
|
.terminal-warning {
|
|
color: var(--warning);
|
|
}
|
|
|
|
.terminal-command {
|
|
color: var(--accent);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.preview-actions {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 1rem 1.5rem;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.preview-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.status-dot {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.status-ready {
|
|
background-color: var(--info);
|
|
}
|
|
|
|
.status-running {
|
|
background-color: var(--warning);
|
|
animation: pulse 1s infinite;
|
|
}
|
|
|
|
.status-success {
|
|
background-color: var(--success);
|
|
}
|
|
|
|
.status-error {
|
|
background-color: var(--error);
|
|
}
|
|
|
|
.preview-buttons {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.vm-status {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
padding: 1.5rem;
|
|
display: none;
|
|
}
|
|
|
|
.vm-status.active {
|
|
display: flex;
|
|
}
|
|
|
|
.vm-card {
|
|
background-color: rgba(30, 41, 59, 0.5);
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.vm-icon {
|
|
width: 3rem;
|
|
height: 3rem;
|
|
background-color: var(--secondary-bg);
|
|
border-radius: 0.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.5rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.vm-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.vm-name {
|
|
font-weight: 600;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.vm-details {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.vm-progress {
|
|
flex: 1;
|
|
height: 4px;
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.vm-progress-bar {
|
|
height: 100%;
|
|
background-color: var(--accent);
|
|
border-radius: 2px;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.vm-state {
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 9999px;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.vm-state-provisioning {
|
|
background-color: rgba(245, 158, 11, 0.1);
|
|
color: var(--warning);
|
|
}
|
|
|
|
.vm-state-running {
|
|
background-color: rgba(16, 185, 129, 0.1);
|
|
color: var(--success);
|
|
}
|
|
|
|
.vm-state-stopping {
|
|
background-color: rgba(239, 68, 68, 0.1);
|
|
color: var(--error);
|
|
}
|
|
|
|
.time-remaining {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
text-align: center;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
.time-progress {
|
|
width: 100%;
|
|
height: 4px;
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
margin-top: 0.75rem;
|
|
}
|
|
|
|
.time-progress-bar {
|
|
height: 100%;
|
|
background-color: var(--accent);
|
|
border-radius: 2px;
|
|
transition: width 1s linear;
|
|
}
|
|
|
|
/* Footer */
|
|
.sandbox-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-top: 2rem;
|
|
padding-top: 1.5rem;
|
|
border-top: 1px solid var(--border);
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.back-to-site {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
color: var(--accent);
|
|
font-weight: 500;
|
|
transition: all var(--transition-normal);
|
|
}
|
|
|
|
.back-to-site:hover {
|
|
color: var(--accent-darker);
|
|
transform: translateX(-3px);
|
|
}
|
|
|
|
/* Animation */
|
|
@keyframes pulse {
|
|
0% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 992px) {
|
|
.sandbox-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.playbook-list {
|
|
max-height: initial;
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.sandbox-header {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.sandbox-actions {
|
|
width: 100%;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.preview-tabs {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.offline-notice {
|
|
display: none;
|
|
background-color: rgba(220, 38, 38, 0.1);
|
|
border: 1px solid rgba(220, 38, 38, 0.3);
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
margin: 1rem 0;
|
|
color: var(--text-primary);
|
|
font-size: 0.9rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.offline-notice-icon {
|
|
background-color: rgba(220, 38, 38, 0.2);
|
|
border-radius: 50%;
|
|
width: 32px;
|
|
height: 32px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 0.75rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.offline-notice-text {
|
|
flex: 1;
|
|
}
|
|
|
|
.offline-notice-text h4 {
|
|
margin: 0 0 0.25rem 0;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.offline-notice-text p {
|
|
margin: 0;
|
|
color: var(--text-secondary);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
/* View tab placeholders */
|
|
.view-placeholder {
|
|
display: none;
|
|
padding: 0;
|
|
height: 100%;
|
|
overflow: auto;
|
|
}
|
|
|
|
.view-placeholder.active {
|
|
display: block;
|
|
}
|
|
|
|
.deployed-site {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: var(--primary-bg);
|
|
}
|
|
|
|
.deployed-header {
|
|
padding: 1.5rem;
|
|
background: linear-gradient(to right, rgba(30, 41, 59, 0.8), rgba(15, 23, 42, 0.9));
|
|
color: white;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.deployed-header h1 {
|
|
font-size: 1.5rem;
|
|
margin: 0 0 0.5rem 0;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.deployed-header p {
|
|
margin: 0;
|
|
font-size: 0.9rem;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.deployed-main {
|
|
flex: 1;
|
|
padding: 1.5rem;
|
|
overflow: auto;
|
|
}
|
|
|
|
.deployed-actions {
|
|
padding: 1rem 1.5rem;
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
border-top: 1px solid var(--border);
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
}
|
|
|
|
.btn-action {
|
|
background-color: var(--secondary-bg);
|
|
color: var(--text-primary);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.5rem;
|
|
padding: 0.5rem 1rem;
|
|
font-size: 0.85rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all var(--transition-normal);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.btn-action:hover {
|
|
background-color: var(--accent);
|
|
color: white;
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
/* Container items for Docker Compose */
|
|
.container-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.container-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 1rem;
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
border-left: 4px solid var(--border);
|
|
}
|
|
|
|
.container-item.running {
|
|
border-left-color: var(--success);
|
|
}
|
|
|
|
.container-item.stopped {
|
|
border-left-color: var(--error);
|
|
}
|
|
|
|
.container-item.restarting {
|
|
border-left-color: var(--warning);
|
|
}
|
|
|
|
.container-icon {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
background-color: var(--secondary-bg);
|
|
border-radius: 0.5rem;
|
|
font-size: 1.25rem;
|
|
margin-right: 1rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.container-name {
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
flex: 1;
|
|
}
|
|
|
|
.container-status {
|
|
margin-right: 1.5rem;
|
|
font-size: 0.85rem;
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 9999px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.running .container-status {
|
|
background-color: rgba(16, 185, 129, 0.1);
|
|
color: var(--success);
|
|
}
|
|
|
|
.stopped .container-status {
|
|
background-color: rgba(239, 68, 68,.1);
|
|
color: var(--error);
|
|
}
|
|
|
|
.restarting .container-status {
|
|
background-color: rgba(245, 158, 11, 0.1);
|
|
color: var(--warning);
|
|
}
|
|
|
|
.container-ports {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
font-family: 'JetBrains Mono', monospace;
|
|
}
|
|
|
|
/* K8s cluster styles */
|
|
.cluster-overview {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2rem;
|
|
}
|
|
|
|
.cluster-section {
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
padding: 1.25rem;
|
|
}
|
|
|
|
.cluster-section h3 {
|
|
margin: 0 0 1rem 0;
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.k8s-items {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.k8s-item {
|
|
display: flex;
|
|
background-color: rgba(15, 23, 42, 0.5);
|
|
padding: 0.75rem 1rem;
|
|
border-radius: 0.35rem;
|
|
font-size: 0.9rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.k8s-name {
|
|
flex: 1;
|
|
font-weight: 500;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
}
|
|
|
|
.k8s-ready {
|
|
width: 5rem;
|
|
color: var(--success);
|
|
}
|
|
|
|
.k8s-role, .k8s-type {
|
|
width: 8rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.k8s-version, .k8s-age {
|
|
color: var(--text-secondary);
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
/* LAMP Stack styles */
|
|
.lamp-status {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.lamp-component {
|
|
display: flex;
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.lamp-icon {
|
|
width: 3rem;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: 1.25rem;
|
|
padding: 1rem 0;
|
|
}
|
|
|
|
.lamp-icon.running {
|
|
background-color: rgba(16, 185, 129, 0.1);
|
|
color: var(--success);
|
|
}
|
|
|
|
.lamp-details {
|
|
padding: 0.75rem 1rem;
|
|
flex: 1;
|
|
}
|
|
|
|
.lamp-name {
|
|
font-weight: 500;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.lamp-info {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.php-info-preview {
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.php-header {
|
|
background-color: rgba(15, 23, 42, 0.5);
|
|
padding: 0.75rem 1rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.php-content {
|
|
padding: 0.75rem 1rem;
|
|
}
|
|
|
|
.php-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.php-table td {
|
|
padding: 0.5rem;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.php-table tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.php-table td:first-child {
|
|
font-weight: 500;
|
|
width: 30%;
|
|
}
|
|
|
|
/* Security check styles */
|
|
.security-checks {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.security-section {
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
padding: 1.25rem;
|
|
}
|
|
|
|
.security-section h3 {
|
|
margin: 0 0 1rem 0;
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.security-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.75rem;
|
|
background-color: rgba(15, 23, 42, 0.5);
|
|
border-radius: 0.35rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.security-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.security-icon {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
border-radius: 0.5rem;
|
|
font-size: 1.25rem;
|
|
margin-right: 1rem;
|
|
}
|
|
|
|
.security-icon.passed {
|
|
background-color: rgba(16, 185, 129, 0.1);
|
|
color: var(--success);
|
|
}
|
|
|
|
.security-icon.warning {
|
|
background-color: rgba(245, 158, 11, 0.1);
|
|
color: var(--warning);
|
|
}
|
|
|
|
.security-icon.failed {
|
|
background-color: rgba(239, 68, 68, 0.1);
|
|
color: var(--error);
|
|
}
|
|
|
|
.security-details {
|
|
flex: 1;
|
|
}
|
|
|
|
.security-name {
|
|
font-weight: 500;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.security-info {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.security-status {
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 9999px;
|
|
background-color: rgba(16, 185, 129, 0.1);
|
|
color: var(--success);
|
|
font-size: 0.8rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Web Server view styles */
|
|
.server-metrics {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.metric-item {
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.metric-label {
|
|
font-size: 0.9rem;
|
|
margin-bottom: 0.5rem;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.metric-bar {
|
|
height: 0.5rem;
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
border-radius: 0.25rem;
|
|
overflow: hidden;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.metric-fill {
|
|
height: 100%;
|
|
background-color: var(--accent);
|
|
border-radius: 0.25rem;
|
|
}
|
|
|
|
.metric-value {
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary);
|
|
text-align: right;
|
|
}
|
|
|
|
/* Simulation mode toggle */
|
|
.simulation-toggle {
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
background-color: var(--bg-card);
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
z-index: 100;
|
|
border: 1px solid var(--border-color);
|
|
}
|
|
|
|
.toggle-label {
|
|
margin-right: 8px;
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.toggle-status {
|
|
margin-left: 8px;
|
|
color: var(--primary);
|
|
font-weight: 500;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.toggle-switch {
|
|
position: relative;
|
|
display: inline-block;
|
|
width: 40px;
|
|
height: 22px;
|
|
margin: 0 0.75rem;
|
|
pointer-events: none; /* Make toggle non-interactive */
|
|
}
|
|
|
|
.toggle-switch input {
|
|
opacity: 0;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
.toggle-slider {
|
|
position: absolute;
|
|
cursor: pointer;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: #374151;
|
|
transition: 0.4s;
|
|
border-radius: 34px;
|
|
}
|
|
|
|
.toggle-slider:before {
|
|
position: absolute;
|
|
content: "";
|
|
height: 16px;
|
|
width: 16px;
|
|
left: 3px;
|
|
bottom: 3px;
|
|
background-color: white;
|
|
transition: 0.4s;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
input:checked + .toggle-slider {
|
|
background-color: var(--accent);
|
|
}
|
|
|
|
input:checked + .toggle-slider:before {
|
|
transform: translateX(18px);
|
|
}
|
|
|
|
.simulation-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-left: auto;
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.toggle-label, .toggle-status {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* Web server styles */
|
|
.website-preview {
|
|
background-color: rgba(15, 23, 42, 0.3);
|
|
border-radius: 0.5rem;
|
|
overflow: hidden;
|
|
height: 300px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.website-header {
|
|
display: flex;
|
|
align-items: center;
|
|
background-color: rgba(15, 23, 42, 0.5);
|
|
padding: 0.5rem 1rem;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.website-controls {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.website-control {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.website-control.close {
|
|
background-color: #ff5f56;
|
|
}
|
|
|
|
.website-control.minimize {
|
|
background-color: #ffbd2e;
|
|
}
|
|
|
|
.website-control.expand {
|
|
background-color: #27c93f;
|
|
}
|
|
|
|
.website-address {
|
|
flex: 1;
|
|
background-color: rgba(15, 23, 42, 0.7);
|
|
border-radius: 0.25rem;
|
|
padding: 0.25rem 0.5rem;
|
|
font-size: 0.8rem;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
color: var(--text-secondary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.website-address i {
|
|
color: var(--accent);
|
|
}
|
|
|
|
.website-content {
|
|
flex: 1;
|
|
padding: 1.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
|
|
.nginx-welcome {
|
|
width: 80px;
|
|
height: 80px;
|
|
margin-bottom: 1rem;
|
|
color: var(--accent);
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.web-title {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
margin-bottom: 0.5rem;
|
|
background: linear-gradient(90deg, var(--accent), #3b82f6);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
}
|
|
|
|
.web-subtitle {
|
|
color: var(--text-secondary);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
/* Additional styles for simulation toggle */
|
|
.simulation-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
padding: 8px 15px;
|
|
background-color: #f1f8ff;
|
|
border-radius: 4px;
|
|
border-left: 3px solid #0078d7;
|
|
}
|
|
|
|
.toggle-label {
|
|
font-weight: 500;
|
|
margin-right: 10px;
|
|
color: #333;
|
|
}
|
|
|
|
.toggle-switch {
|
|
position: relative;
|
|
display: inline-block;
|
|
width: 50px;
|
|
height: 24px;
|
|
}
|
|
|
|
.toggle-switch input {
|
|
opacity: 0;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
.toggle-slider {
|
|
position: absolute;
|
|
cursor: pointer;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: #ccc;
|
|
transition: .4s;
|
|
border-radius: 24px;
|
|
}
|
|
|
|
.toggle-slider:before {
|
|
position: absolute;
|
|
content: "";
|
|
height: 16px;
|
|
width: 16px;
|
|
left: 4px;
|
|
bottom: 4px;
|
|
background-color: white;
|
|
transition: .4s;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
input:checked + .toggle-slider {
|
|
background-color: #2196F3;
|
|
}
|
|
|
|
input:focus + .toggle-slider {
|
|
box-shadow: 0 0 1px #2196F3;
|
|
}
|
|
|
|
input:checked + .toggle-slider:before {
|
|
transform: translateX(26px);
|
|
}
|
|
|
|
.toggle-status {
|
|
margin-left: 10px;
|
|
font-weight: 500;
|
|
color: #2196F3;
|
|
}
|
|
|
|
.simulation-mode .preview-view {
|
|
position: relative;
|
|
}
|
|
|
|
.simulation-mode .preview-view:after {
|
|
content: "Simulation Mode";
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 10px;
|
|
background-color: #ffbf00;
|
|
color: #333;
|
|
padding: 3px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.live-indicator {
|
|
width: 8px;
|
|
height: 8px;
|
|
background-color: var(--success);
|
|
border-radius: 50%;
|
|
position: relative;
|
|
}
|
|
|
|
.live-indicator.offline {
|
|
background-color: var(--error);
|
|
}
|
|
|
|
.live-indicator::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 50%;
|
|
background-color: var(--success);
|
|
animation: pulse 2s infinite;
|
|
z-index: -1;
|
|
}
|
|
|
|
.live-indicator.offline::after {
|
|
background-color: var(--error);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- Navigation Bar -->
|
|
<nav class="navbar">
|
|
<div class="container">
|
|
<div class="logo">
|
|
<a href="index.html">
|
|
<span class="logo-text-glow">ArgoBox</span><span class="logo-dot-glow">.com</span>
|
|
</a>
|
|
</div>
|
|
<div class="nav-menu">
|
|
<a href="index.html#home" class="nav-link">Home</a>
|
|
<a href="index.html#technologies" class="nav-link">Technologies</a>
|
|
<a href="index.html#services" class="nav-link">Services</a>
|
|
<a href="index.html#projects" class="nav-link">Projects</a>
|
|
<a href="index.html#dashboards" class="nav-link">Dashboards</a>
|
|
<a href="index.html#contact" class="nav-link">Contact</a>
|
|
</div>
|
|
<div class="nav-buttons">
|
|
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
|
<span class="live-indicator offline"></span>
|
|
<span>Live Dashboard</span>
|
|
</a>
|
|
<button class="menu-toggle" aria-label="Toggle menu">
|
|
<i class="fas fa-bars"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Top Links -->
|
|
<div class="top-links">
|
|
<a href="https://laforceit.com" class="laforceit-link">
|
|
<span class="logo-text-glow">LaForceIT</span><span class="logo-dot-glow">.com</span>
|
|
</a>
|
|
<a href="construction.html" class="signin-button" target="_blank">
|
|
<i class="fas fa-sign-in-alt"></i>
|
|
<span>Sign In</span>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Sandbox Content -->
|
|
<div class="sandbox-container">
|
|
<div class="container">
|
|
<!-- Simulation Mode Toggle -->
|
|
<div class="simulation-toggle">
|
|
<span class="toggle-label">Simulation Mode</span>
|
|
<label class="toggle-switch">
|
|
<input type="checkbox" id="simulation-toggle" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<span class="toggle-status">Active</span>
|
|
</div>
|
|
|
|
<!-- Offline Notice -->
|
|
<div class="offline-notice">
|
|
<div class="offline-notice-icon">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
</div>
|
|
<div class="offline-notice-text">
|
|
<h3>Ansible Sandbox is Currently Offline</h3>
|
|
<p>The Ansible Sandbox environment is currently in simulation mode. You can explore the interface, but actual deployments are not available at this time. We're working to bring the full functionality online soon.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sandbox-header">
|
|
<div class="sandbox-title">
|
|
<h1>Ansible Sandbox</h1>
|
|
</div>
|
|
|
|
<div class="sandbox-actions">
|
|
<a href="ansible-help.html" class="sandbox-btn">
|
|
<i class="fas fa-question-circle"></i>
|
|
<span>Help</span>
|
|
</a>
|
|
<a href="ansible-docs.html" class="sandbox-btn">
|
|
<i class="fas fa-book"></i>
|
|
<span>Documentation</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sandbox-grid">
|
|
<div class="playbook-list">
|
|
<div class="playbook-card active" data-playbook="web-server">
|
|
<div class="playbook-header">
|
|
<h3 class="playbook-title">Web Server Deployment</h3>
|
|
<span class="playbook-tag">Basic</span>
|
|
</div>
|
|
<p class="playbook-description">
|
|
Deploy a Nginx web server with a sample website in a controlled environment.
|
|
</p>
|
|
<div class="playbook-details">
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-clock"></i>
|
|
<span>Runtime: ~3 min</span>
|
|
</div>
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-server"></i>
|
|
<span>1 VM</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="playbook-card" data-playbook="docker-compose">
|
|
<div class="playbook-header">
|
|
<h3 class="playbook-title">Docker Compose Stack</h3>
|
|
<span class="playbook-tag">Intermediate</span>
|
|
</div>
|
|
<p class="playbook-description">
|
|
Deploy a multi-container application using Docker Compose with automatic configuration.
|
|
</p>
|
|
<div class="playbook-details">
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-clock"></i>
|
|
<span>Runtime: ~5 min</span>
|
|
</div>
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-server"></i>
|
|
<span>1 VM</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="playbook-card" data-playbook="k3s-cluster">
|
|
<div class="playbook-header">
|
|
<h3 class="playbook-title">K3s Kubernetes Cluster</h3>
|
|
<span class="playbook-tag">Advanced</span>
|
|
</div>
|
|
<p class="playbook-description">
|
|
Deploy a lightweight Kubernetes cluster with basic services and sample application.
|
|
</p>
|
|
<div class="playbook-details">
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-clock"></i>
|
|
<span>Runtime: ~8 min</span>
|
|
</div>
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-server"></i>
|
|
<span>3 VMs</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="playbook-card" data-playbook="lamp-stack">
|
|
<div class="playbook-header">
|
|
<h3 class="playbook-title">LAMP Stack</h3>
|
|
<span class="playbook-tag">Intermediate</span>
|
|
</div>
|
|
<p class="playbook-description">
|
|
Deploy a Linux, Apache, MySQL, and PHP stack with a sample application.
|
|
</p>
|
|
<div class="playbook-details">
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-clock"></i>
|
|
<span>Runtime: ~4 min</span>
|
|
</div>
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-server"></i>
|
|
<span>1 VM</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="playbook-card" data-playbook="security-hardening">
|
|
<div class="playbook-header">
|
|
<h3 class="playbook-title">Security Hardening</h3>
|
|
<span class="playbook-tag">Advanced</span>
|
|
</div>
|
|
<p class="playbook-description">
|
|
Apply security best practices to a Linux server including firewall, SSH hardening, and more.
|
|
</p>
|
|
<div class="playbook-details">
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-clock"></i>
|
|
<span>Runtime: ~6 min</span>
|
|
</div>
|
|
<div class="playbook-detail">
|
|
<i class="fas fa-server"></i>
|
|
<span>1 VM</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sandbox-preview">
|
|
<div class="preview-container">
|
|
<div class="preview-header">
|
|
<div class="preview-title">
|
|
<i class="fas fa-file-code"></i>
|
|
<span>Web Server Deployment</span>
|
|
</div>
|
|
<div class="preview-tabs">
|
|
<div class="preview-tab active" data-tab="code">Playbook</div>
|
|
<div class="preview-tab" data-tab="config">Configuration</div>
|
|
<div class="preview-tab" data-tab="output">Output</div>
|
|
<div class="preview-tab" data-tab="status">VM Status</div>
|
|
<div class="preview-tab" data-tab="view">View</div>
|
|
</div>
|
|
</div>
|
|
<div class="preview-content">
|
|
<div class="tab-content active" id="code-tab">
|
|
<div class="code-editor">
|
|
<div class="code-line">
|
|
<span class="line-number">1</span>
|
|
<span class="line-content code-comment">---</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">2</span>
|
|
<span class="line-content code-comment"># Web Server Deployment Playbook</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">3</span>
|
|
<span class="line-content code-comment"># This playbook installs and configures a basic Nginx web server</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">4</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">5</span>
|
|
<span class="line-content">- <span class="code-key">name</span>: <span class="code-string">Deploy Web Server</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">6</span>
|
|
<span class="line-content"> <span class="code-key">hosts</span>: <span class="code-value">all</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">7</span>
|
|
<span class="line-content"> <span class="code-key">become</span>: <span class="code-value">yes</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">8</span>
|
|
<span class="line-content"> <span class="code-key">vars</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">9</span>
|
|
<span class="line-content"> <span class="code-key">web_domain</span>: <span class="code-string">example.local</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">10</span>
|
|
<span class="line-content"> <span class="code-key">web_root</span>: <span class="code-string">/var/www/html</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">11</span>
|
|
<span class="line-content"> <span class="code-key">enable_https</span>: <span class="code-value">false</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">12</span>
|
|
<span class="line-content"> <span class="code-key">web_color</span>: <span class="code-string">blue</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">13</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">14</span>
|
|
<span class="line-content"> <span class="code-key">tasks</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">15</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Update apt cache</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">16</span>
|
|
<span class="line-content"> <span class="code-key">apt</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">17</span>
|
|
<span class="line-content"> <span class="code-key">update_cache</span>: <span class="code-value">yes</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">18</span>
|
|
<span class="line-content"> <span class="code-key">cache_valid_time</span>: <span class="code-value">3600</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">19</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">20</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Install Nginx and required packages</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">21</span>
|
|
<span class="line-content"> <span class="code-key">apt</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">22</span>
|
|
<span class="line-content"> <span class="code-key">name</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">23</span>
|
|
<span class="line-content"> - <span class="code-string">nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">24</span>
|
|
<span class="line-content"> - <span class="code-string">curl</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">25</span>
|
|
<span class="line-content"> <span class="code-key">state</span>: <span class="code-string">present</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">26</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">27</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Create web root directory</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">28</span>
|
|
<span class="line-content"> <span class="code-key">file</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">29</span>
|
|
<span class="line-content"> <span class="code-key">path</span>: <span class="code-string">"{{ web_root }}"</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">30</span>
|
|
<span class="line-content"> <span class="code-key">state</span>: <span class="code-string">directory</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">31</span>
|
|
<span class="line-content"> <span class="code-key">mode</span>: <span class="code-string">'0755'</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">32</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">33</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Create sample website</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">34</span>
|
|
<span class="line-content"> <span class="code-key">template</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">35</span>
|
|
<span class="line-content"> <span class="code-key">src</span>: <span class="code-string">templates/index.html.j2</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">36</span>
|
|
<span class="line-content"> <span class="code-key">dest</span>: <span class="code-string">"{{ web_root }}/index.html"</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">37</span>
|
|
<span class="line-content"> <span class="code-key">mode</span>: <span class="code-string">'0644'</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">38</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">39</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Configure Nginx virtual host</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">40</span>
|
|
<span class="line-content"> <span class="code-key">template</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">41</span>
|
|
<span class="line-content"> <span class="code-key">src</span>: <span class="code-string">templates/nginx.conf.j2</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">42</span>
|
|
<span class="line-content"> <span class="code-key">dest</span>: <span class="code-string">/etc/nginx/sites-available/{{ web_domain }}</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">43</span>
|
|
<span class="line-content"> <span class="code-key">notify</span>: <span class="code-string">restart nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">44</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">45</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Enable Nginx virtual host</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">46</span>
|
|
<span class="line-content"> <span class="code-key">file</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">47</span>
|
|
<span class="line-content"> <span class="code-key">src</span>: <span class="code-string">/etc/nginx/sites-available/{{ web_domain }}</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">48</span>
|
|
<span class="line-content"> <span class="code-key">dest</span>: <span class="code-string">/etc/nginx/sites-enabled/{{ web_domain }}</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">49</span>
|
|
<span class="line-content"> <span class="code-key">state</span>: <span class="code-string">link</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">50</span>
|
|
<span class="line-content"> <span class="code-key">notify</span>: <span class="code-string">restart nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">51</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">52</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">Start Nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">53</span>
|
|
<span class="line-content"> <span class="code-key">service</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">54</span>
|
|
<span class="line-content"> <span class="code-key">name</span>: <span class="code-string">nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">55</span>
|
|
<span class="line-content"> <span class="code-key">state</span>: <span class="code-string">started</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">56</span>
|
|
<span class="line-content"> <span class="code-key">enabled</span>: <span class="code-value">yes</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">57</span>
|
|
<span class="line-content"></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">58</span>
|
|
<span class="line-content"> <span class="code-key">handlers</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">59</span>
|
|
<span class="line-content"> - <span class="code-key">name</span>: <span class="code-string">restart nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">60</span>
|
|
<span class="line-content"> <span class="code-key">service</span>:</span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">61</span>
|
|
<span class="line-content"> <span class="code-key">name</span>: <span class="code-string">nginx</span></span>
|
|
</div>
|
|
<div class="code-line">
|
|
<span class="line-number">62</span>
|
|
<span class="line-content"> <span class="code-key">state</span>: <span class="code-string">restarted</span></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-content" id="config-tab">
|
|
<div class="preview-form">
|
|
<div class="form-group">
|
|
<label class="form-label" for="web_domain">Web Domain</label>
|
|
<input type="text" id="web_domain" class="form-control" value="example.local">
|
|
<div class="form-text">Domain name for the Nginx virtual host.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label" for="web_root">Web Root</label>
|
|
<input type="text" id="web_root" class="form-control" value="/var/www/html">
|
|
<div class="form-text">Directory path where website files will be stored.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Enable HTTPS</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="enable_https">
|
|
<label class="form-check-label" for="enable_https">
|
|
Configure HTTPS with self-signed certificate
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label" for="web_color">Theme Color</label>
|
|
<select id="web_color" class="form-control form-select">
|
|
<option value="blue" selected>Blue</option>
|
|
<option value="green">Green</option>
|
|
<option value="red">Red</option>
|
|
<option value="purple">Purple</option>
|
|
</select>
|
|
<div class="form-text">Color theme for the sample website.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label" for="vm_template">VM Template</label>
|
|
<select id="vm_template" class="form-control form-select">
|
|
<option value="ubuntu-22.04" selected>Ubuntu 22.04 LTS</option>
|
|
<option value="debian-11">Debian 11</option>
|
|
<option value="centos-stream-9">CentOS Stream 9</option>
|
|
</select>
|
|
<div class="form-text">Operating system for the virtual machine.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label" for="vm_resources">VM Resources</label>
|
|
<select id="vm_resources" class="form-control form-select">
|
|
<option value="small" selected>Small (1 vCPU, 1GB RAM)</option>
|
|
<option value="medium">Medium (2 vCPU, 2GB RAM)</option>
|
|
<option value="large">Large (4 vCPU, 4GB RAM)</option>
|
|
</select>
|
|
<div class="form-text">Resource allocation for the virtual machine.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-content" id="output-tab">
|
|
<div class="terminal">
|
|
<span class="terminal-line">PLAY [Deploy Web Server] ***************************************************</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Gathering Facts] *****************************************************</span>
|
|
<span class="terminal-line terminal-success">ok: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Update apt cache] ****************************************************</span>
|
|
<span class="terminal-line terminal-success">ok: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Install Nginx and required packages] ********************************</span>
|
|
<span class="terminal-line terminal-success">ok: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Create web root directory] *******************************************</span>
|
|
<span class="terminal-line terminal-success">ok: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Create sample website] ***********************************************</span>
|
|
<span class="terminal-line terminal-success">changed: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Configure Nginx virtual host] ****************************************</span>
|
|
<span class="terminal-line terminal-success">changed: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Enable Nginx virtual host] *******************************************</span>
|
|
<span class="terminal-line terminal-success">changed: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">TASK [Start Nginx] *********************************************************</span>
|
|
<span class="terminal-line terminal-success">ok: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">RUNNING HANDLER [restart nginx] ********************************************</span>
|
|
<span class="terminal-line terminal-success">changed: [webserver]</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">PLAY RECAP *****************************************************************</span>
|
|
<span class="terminal-line terminal-success">webserver : ok=9 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0</span>
|
|
<span class="terminal-line"></span>
|
|
<span class="terminal-line">VERIFICATION **************************************************************</span>
|
|
<span class="terminal-line">Testing website availability...</span>
|
|
<span class="terminal-line terminal-success">Website is accessible at: http://192.168.122.10</span>
|
|
<span class="terminal-line terminal-success">Website deployed successfully!</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-content" id="status-tab">
|
|
<div class="vm-status active">
|
|
<div class="vm-card">
|
|
<div class="vm-icon">
|
|
<i class="fas fa-server"></i>
|
|
</div>
|
|
<div class="vm-info">
|
|
<div class="vm-name">webserver (Ubuntu 22.04 LTS)</div>
|
|
<div class="vm-details">1 vCPU, 1GB RAM, 20GB Storage</div>
|
|
<div class="vm-progress">
|
|
<div class="vm-progress-bar" style="width: 100%;"></div>
|
|
</div>
|
|
</div>
|
|
<div class="vm-state vm-state-running">Running</div>
|
|
</div>
|
|
|
|
<div class="time-remaining">
|
|
<div>Sandbox environment active for 15 more minutes</div>
|
|
<div class="time-progress">
|
|
<div class="time-progress-bar" style="width: 75%;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add new View tab -->
|
|
<div class="tab-content" id="view-tab">
|
|
<!-- Web Server View Placeholder -->
|
|
<div class="view-placeholder" id="web-server-view">
|
|
<div class="deployed-site">
|
|
<div class="deployed-header">
|
|
<h1>Deployed Web Server</h1>
|
|
<p>Your Nginx web server has been successfully deployed and is now running</p>
|
|
</div>
|
|
<div class="deployed-main">
|
|
<div class="server-metrics">
|
|
<div class="metric-item">
|
|
<div class="metric-label">
|
|
<div>CPU Usage</div>
|
|
<div>15%</div>
|
|
</div>
|
|
<div class="metric-bar">
|
|
<div class="metric-fill" style="width: 15%"></div>
|
|
</div>
|
|
<div class="metric-value">59MB / 1GB</div>
|
|
</div>
|
|
<div class="metric-item">
|
|
<div class="metric-label">
|
|
<div>Memory Usage</div>
|
|
<div>23%</div>
|
|
</div>
|
|
<div class="metric-bar">
|
|
<div class="metric-fill" style="width: 23%"></div>
|
|
</div>
|
|
<div class="metric-value">241MB / 1GB</div>
|
|
</div>
|
|
<div class="metric-item">
|
|
<div class="metric-label">
|
|
<div>Disk Usage</div>
|
|
<div>8%</div>
|
|
</div>
|
|
<div class="metric-bar">
|
|
<div class="metric-fill" style="width: 8%"></div>
|
|
</div>
|
|
<div class="metric-value">1.6GB / 20GB</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="website-preview">
|
|
<div class="website-header">
|
|
<div class="website-controls">
|
|
<div class="website-control close"></div>
|
|
<div class="website-control minimize"></div>
|
|
<div class="website-control expand"></div>
|
|
</div>
|
|
<div class="website-address">
|
|
<i class="fas fa-lock"></i>
|
|
http://192.168.122.10
|
|
</div>
|
|
</div>
|
|
<div class="website-content">
|
|
<i class="fas fa-server nginx-welcome"></i>
|
|
<div class="web-title">Welcome to nginx!</div>
|
|
<div class="web-subtitle">Deployed with Ansible automation</div>
|
|
<p>If you see this page, the nginx web server is successfully installed and working.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="deployed-actions">
|
|
<button class="btn-action">
|
|
<i class="fas fa-sync-alt"></i>
|
|
Refresh Status
|
|
</button>
|
|
<button class="btn-action">
|
|
<i class="fas fa-external-link-alt"></i>
|
|
Open in New Tab
|
|
</button>
|
|
<button class="btn-action">
|
|
<i class="fas fa-terminal"></i>
|
|
SSH to Server
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div> |