Compare commits
No commits in common. "40bac1987a866d8bcda94c85fcb11c2022816480" and "1398122e3b541a15877ec049115652779b4cef26" have entirely different histories.
40bac1987a
...
1398122e3b
3 changed files with 15 additions and 108 deletions
|
|
@ -8,7 +8,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: [docker]
|
runs-on: [self-hosted]
|
||||||
env:
|
env:
|
||||||
BRANCH: ${{ github.ref_name }}
|
BRANCH: ${{ github.ref_name }}
|
||||||
COMMIT: ${{ github.sha }}
|
COMMIT: ${{ github.sha }}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,12 @@ It offers a clean, interactive menu for common Docker operations like pulling im
|
||||||
|
|
||||||
- 🔹 **Interactive container management** — start, stop, remove, or attach to containers with simple numbered menus.
|
- 🔹 **Interactive container management** — start, stop, remove, or attach to containers with simple numbered menus.
|
||||||
- 🔹 **Port mapping made clear** — automatically prompts for and explains host ↔ container port bindings.
|
- 🔹 **Port mapping made clear** — automatically prompts for and explains host ↔ container port bindings.
|
||||||
- 🔹 **Image operations** — pull, list, and delete Docker images; curated pull list (Debian, Ubuntu, Rocky Linux, Alpine) plus a custom entry to grab common bases without retyping them.
|
- 🔹 **Image operations** — pull, list, and delete Docker images.
|
||||||
- 🔹 **Script-to-image workflow** — turn a bash setup script into a Dockerfile and build the resulting image in one go.
|
- 🔹 **Script-to-image workflow** — turn a bash setup script into a Dockerfile and build the resulting image in one go.
|
||||||
- 🔹 **Quick MySQL setup** — spin up a MySQL container with version, password, and port configuration in seconds.
|
- 🔹 **Quick MySQL setup** — spin up a MySQL container with version, password, and port configuration in seconds.
|
||||||
- 🔹 **Get container IP address** — cleanly retrieves and displays only the container’s assigned IP.
|
- 🔹 **Get container IP address** — cleanly retrieves and displays only the container’s assigned IP.
|
||||||
- 🔹 **Run detached commands** — execute background jobs inside a container without attaching an interactive shell.
|
- 🔹 **Run detached commands** — execute background jobs inside a container without attaching an interactive shell.
|
||||||
- 🔹 **Modern C++ design** — built with classes, minimal dependencies, and clear abstractions.
|
- 🔹 **Modern C++ design** — built with classes, minimal dependencies, and clear abstractions.
|
||||||
- 🔹 **Interactive run flow** — lists pulled images with numeric selection, allows entering a custom image name, and keeps the port-mapping explanation in place before launching `/bin/sh`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -114,8 +113,6 @@ private:
|
||||||
static void runCommand(const std::string& cmd);
|
static void runCommand(const std::string& cmd);
|
||||||
std::vector<std::pair<std::string, std::string>> getContainerList() const;
|
std::vector<std::pair<std::string, std::string>> getContainerList() const;
|
||||||
std::string selectContainer(const std::string& prompt);
|
std::string selectContainer(const std::string& prompt);
|
||||||
/* NEW helper – retrieves all images */
|
|
||||||
std::vector<std::pair<std::string, std::string>> getImageList() const;
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -136,7 +133,6 @@ private:
|
||||||
- `showContainerIP` — display a container’s IP address.
|
- `showContainerIP` — display a container’s IP address.
|
||||||
- `runCommand` — helper to invoke shell commands.
|
- `runCommand` — helper to invoke shell commands.
|
||||||
- `getContainerList` — retrieve Docker container IDs and names for selection menus.
|
- `getContainerList` — retrieve Docker container IDs and names for selection menus.
|
||||||
- `getImageList` — gather local Docker image IDs and names for menus and reporting.
|
|
||||||
- `selectContainer` — present a menu to pick a container interactively.
|
- `selectContainer` — present a menu to pick a container interactively.
|
||||||
|
|
||||||
This makes the codebase **extensible** — adding new Docker features like `docker logs` or `docker stats` requires only a small new method.
|
This makes the codebase **extensible** — adding new Docker features like `docker logs` or `docker stats` requires only a small new method.
|
||||||
|
|
|
||||||
115
main.cpp
115
main.cpp
|
|
@ -31,8 +31,6 @@ private:
|
||||||
static void runCommand(const string& cmd);
|
static void runCommand(const string& cmd);
|
||||||
vector<pair<string, string>> getContainerList() const;
|
vector<pair<string, string>> getContainerList() const;
|
||||||
string selectContainer(const string& prompt);
|
string selectContainer(const string& prompt);
|
||||||
/* NEW helper – retrieves all images */
|
|
||||||
vector<pair<string, string>> getImageList() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------- Core Utility ----------------
|
// ---------------- Core Utility ----------------
|
||||||
|
|
@ -41,24 +39,6 @@ void DockerManager::runCommand(const string& cmd) {
|
||||||
system(cmd.c_str());
|
system(cmd.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<pair<string, string>> DockerManager::getImageList() const {
|
|
||||||
vector<pair<string, string>> images;
|
|
||||||
array<char, 256> buffer{};
|
|
||||||
string result;
|
|
||||||
FILE* pipe = popen("docker images --format '{{.ID}} {{.Repository}}:{{.Tag}}'", "r");
|
|
||||||
if (!pipe) return images;
|
|
||||||
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
|
|
||||||
result = buffer.data();
|
|
||||||
stringstream ss(result);
|
|
||||||
string id, repoTag;
|
|
||||||
ss >> id >> repoTag;
|
|
||||||
if (!id.empty() && !repoTag.empty())
|
|
||||||
images.emplace_back(id, repoTag);
|
|
||||||
}
|
|
||||||
pclose(pipe);
|
|
||||||
return images;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<pair<string, string>> DockerManager::getContainerList() const {
|
vector<pair<string, string>> DockerManager::getContainerList() const {
|
||||||
vector<pair<string, string>> containers;
|
vector<pair<string, string>> containers;
|
||||||
array<char, 256> buffer{};
|
array<char, 256> buffer{};
|
||||||
|
|
@ -106,71 +86,21 @@ string DockerManager::selectContainer(const string& prompt) {
|
||||||
// ---------------- Docker Actions ----------------
|
// ---------------- Docker Actions ----------------
|
||||||
|
|
||||||
void DockerManager::pullImage() {
|
void DockerManager::pullImage() {
|
||||||
const vector<string> images = {"debian:stable", "ubuntu:noble", "rockylinux:9.3", "alpine:latest"};
|
|
||||||
|
|
||||||
cout << "\nSelect Docker image to pull:\n";
|
|
||||||
for (size_t i = 0; i < images.size(); ++i) cout << i + 1 << ". " << images[i] << "\n";
|
|
||||||
cout << images.size() + 1 << ". Enter custom image\n";
|
|
||||||
cout << "Choose an option (1-" << images.size() + 1 << "): ";
|
|
||||||
|
|
||||||
int choice;
|
|
||||||
cin >> choice;
|
|
||||||
|
|
||||||
string image;
|
string image;
|
||||||
if (choice >= 1 && choice <= static_cast<int>(images.size())) {
|
cout << "Enter Docker image to pull (e.g., alpine): ";
|
||||||
image = images[choice - 1];
|
cin >> image;
|
||||||
} else if (choice == static_cast<int>(images.size()) + 1) {
|
|
||||||
cout << "Enter custom Docker image name: ";
|
|
||||||
cin >> image;
|
|
||||||
} else {
|
|
||||||
cout << "Invalid selection. Aborting.\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Pulling image: " << image << "\n";
|
|
||||||
runCommand("docker pull " + image);
|
runCommand("docker pull " + image);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockerManager::runContainerInteractive() {
|
void DockerManager::runContainerInteractive() {
|
||||||
// Get list of available images
|
|
||||||
auto images = getImageList();
|
|
||||||
string image;
|
string image;
|
||||||
|
cout << "Enter Docker image to run interactively (e.g., alpine): ";
|
||||||
if (images.empty()) {
|
cin >> image;
|
||||||
cout << "No Docker images found. Please pull an image first.\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display available images
|
|
||||||
cout << "\nAvailable Docker Images:\n";
|
|
||||||
int idx = 1;
|
|
||||||
for (const auto& img : images) {
|
|
||||||
cout << idx++ << ". " << img.second << " (" << img.first.substr(0, 12) << ")\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prompt user to select or enter custom image
|
|
||||||
cout << idx << ". Enter custom Docker image name\n";
|
|
||||||
cout << "Choose an option (1-" << images.size() << " or " << idx << "): ";
|
|
||||||
|
|
||||||
int choice;
|
|
||||||
cin >> choice;
|
|
||||||
|
|
||||||
if (choice >= 1 && choice <= static_cast<int>(images.size())) {
|
|
||||||
// User selected an existing image
|
|
||||||
image = images[choice - 1].second;
|
|
||||||
} else if (choice == idx) {
|
|
||||||
// User wants to enter custom image name
|
|
||||||
cout << "Enter custom Docker image name: ";
|
|
||||||
cin >> image;
|
|
||||||
} else {
|
|
||||||
cout << "Invalid selection. Aborting.\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue with port mapping
|
|
||||||
int portCount;
|
int portCount;
|
||||||
cout << "How many port mappings? ";
|
cout << "How many port mappings? ";
|
||||||
cin >> portCount;
|
cin >> portCount;
|
||||||
|
|
||||||
vector<string> ports;
|
vector<string> ports;
|
||||||
for (int i = 0; i < portCount; ++i) {
|
for (int i = 0; i < portCount; ++i) {
|
||||||
string port;
|
string port;
|
||||||
|
|
@ -179,11 +109,14 @@ void DockerManager::runContainerInteractive() {
|
||||||
cin >> port;
|
cin >> port;
|
||||||
ports.push_back("-p " + port);
|
ports.push_back("-p " + port);
|
||||||
}
|
}
|
||||||
|
|
||||||
string portArgs;
|
string portArgs;
|
||||||
for (const auto& p : ports) portArgs += p + " ";
|
for (const auto& p : ports) portArgs += p + " ";
|
||||||
|
|
||||||
cout << "\nPort Forwarding Explanation:\n"
|
cout << "\nPort Forwarding Explanation:\n"
|
||||||
<< " '-p hostPort:containerPort' exposes the container’s port to the host.\n"
|
<< " '-p hostPort:containerPort' exposes the container’s port to the host.\n"
|
||||||
<< " Example: '-p 8080:80' allows access via http://localhost:8080\n\n";
|
<< " Example: '-p 8080:80' allows access via http://localhost:8080\n\n";
|
||||||
|
|
||||||
runCommand("docker run -it " + portArgs + image + " /bin/sh");
|
runCommand("docker run -it " + portArgs + image + " /bin/sh");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,31 +134,10 @@ void DockerManager::startDetached() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockerManager::deleteImage() {
|
void DockerManager::deleteImage() {
|
||||||
auto images = getImageList();
|
string image;
|
||||||
if (images.empty()) {
|
cout << "Enter image name or ID to delete: ";
|
||||||
cout << "No Docker images found.\n";
|
cin >> image;
|
||||||
return;
|
runCommand("docker rmi " + image);
|
||||||
}
|
|
||||||
|
|
||||||
cout << "\nAvailable Images:\n";
|
|
||||||
int idx = 1;
|
|
||||||
for (const auto& img : images) {
|
|
||||||
cout << idx++ << ". " << img.second << " (" << img.first.substr(0, 12) << ")\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int choice;
|
|
||||||
cout << "Select image to delete (1-" << images.size() << "): ";
|
|
||||||
cin >> choice;
|
|
||||||
|
|
||||||
if (choice < 1 || choice > static_cast<int>(images.size())) {
|
|
||||||
cout << "Invalid selection.\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& id = images[choice - 1].first;
|
|
||||||
cout << "Deleting image: " << images[choice - 1].second
|
|
||||||
<< " (ID: " << id << ") ...\n";
|
|
||||||
runCommand("docker rmi " + id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockerManager::stopContainer() {
|
void DockerManager::stopContainer() {
|
||||||
|
|
@ -427,4 +339,3 @@ int main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue