├── .env_Template ├── .gitignore ├── 20.04 └── Vagrantfile ├── README.md ├── Vagrantfile ├── Vagrantfile01 ├── Vagrantfile_1604 ├── Vagrantfile_20240226 ├── Vagrantfile_back ├── advisor └── docker-compose.yml ├── ctl.sh ├── go.mod ├── go.sum ├── main.go ├── provisioning ├── docker.sh ├── docker.sh_bak ├── provision.ps1 └── useradd_perm.sh ├── static ├── index.html ├── script.js └── style.css ├── vvmanager └── webconsole.sh /.env_Template: -------------------------------------------------------------------------------- 1 | ## Please make sure the Network information as below 2 | Public_IP= 3 | Private_IP= 4 | PASSWORD== 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | *.log 3 | resource.status 4 | .env 5 | output.log 6 | history.log 7 | history.log.1 8 | history.log.2 9 | history.log.3 10 | history.log.4 11 | history.log.5 12 | resource.status 13 | vvmanager.pid 14 | -------------------------------------------------------------------------------- /20.04/Vagrantfile: -------------------------------------------------------------------------------- 1 | OS_NAME="ubuntu/focal64" 2 | NODE_COUNT = 10 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.network "private_network", :name => 'vboxnet9' 6 | config.vm.synced_folder "~/.ssh/", "/tmp/conf.d/" 7 | config.vm.provision "shell", path: "./docker.sh", args: "" 8 | NODE_COUNT.times do |i| 9 | node_id = "docker0#{i}.dev" 10 | config.vm.network "private_network", ip: "10.22.34.1#{i}", :adapter => 2 11 | config.vm.define node_id do |node| 12 | node.vm.box = OS_NAME 13 | node.vm.hostname = "#{node_id}" 14 | end 15 | end 16 | config.vm.provider :virtualbox do |vb| 17 | vb.customize ["modifyvm", :id, "--memory", "4096"] 18 | vb.customize ["modifyvm", :id, "--cpus", "2"] 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vagrant_docker_cluster 2 | 3 | ## CLI mode version 4 | 5 | ### Prerequisites 6 | - Go 1.16 or higher 7 | - Vagrant 8 | - VirtualBox 9 | - Git 10 | 11 | ### Auto-Install & use(For the Macbook User or Linux) 12 | * Clone the repository: 13 | 14 | ```sh 15 | git clone git@github.com:ralfyang/vagrant_docker_cluster.git 16 | cd vagrant_docker_cluster 17 | ``` 18 | 19 | [![asciicast](https://asciinema.org/a/78LKZjwwx0dMM595q0GqhDrvw.png)](https://asciinema.org/a/78LKZjwwx0dMM595q0GqhDrvw) 20 | 21 | ``` 22 | $ ./ctl.sh 23 | =========================================================== 24 | What do you want ? 25 | =========================================================== 26 | [0] Install the Virtualbox & Vagrant <--- HERE! 27 | [1] Start VM & login 28 | [2] Login to VM 29 | [3] Stop VM 30 | [4] Reload VM 31 | [5] Reboot VM 32 | [RM] Remove VM 33 | =========================================================== 34 | Please insert a key as you need 35 | =========================================================== 36 | 37 | ``` 38 | 39 | ## Install the Requirements - Manual 40 | ### Virtual Box install 41 | * https://www.virtualbox.org/wiki/Downloads 42 | 43 | ### Vagrant install 44 | * https://www.vagrantup.com/downloads.html 45 | 46 | 47 | ## Vagrant VM create 48 | ``` 49 | vagrant up docker01.dev 50 | ``` 51 | or 52 | 53 | ``` 54 | vagrant up docker0{1..9}.dev 55 | ``` 56 | 57 | 58 | ### ssh-keygen - if you need to create ssh-key as below 59 | ``` 60 | ssh-keygen 61 | 62 | Generating public/private rsa key pair. 63 | Enter file in which to save the key (/Users/ralfyang/.ssh/id_rsa): 64 | Created directory '/Users/ralfyang/.ssh'. 65 | Enter passphrase (empty for no passphrase): 66 | Enter same passphrase again: 67 | Your identification has been saved in /Users/ralfyang/.ssh/id_rsa. 68 | Your public key has been saved in /Users/ralfyang/.ssh/id_rsa.pub. 69 | The key fingerprint is: 70 | ``` 71 | 72 | ### How to login 73 | ``` 74 | vagrant ssh docker01.dev 75 | ``` 76 | 77 | ## web-console mode 78 | * setup the `.env` file as below 79 | ``` 80 | ## Please make sure the Network information as below 81 | Public_IP=111.111.111.2 82 | Private_IP=192.168.100.13 83 | PASSWORD=your_password_for_webconsole_login 84 | ``` 85 | 86 | * Running the webconsole for test 87 | ``` 88 | nohup go run ./main.go > output.log 2>&1 & 89 | ``` 90 | 91 | * Demo 92 | ![image](https://github.com/ralfyang/vagrant_docker_cluster/assets/4043594/eb3390cd-2551-4663-ad20-059d170e8786) 93 | 94 | 95 | 96 | ## Vagrant Web Console version 97 | 98 | This project provides a web console for managing Vagrant VMs. The console allows you to start, stop, reload, reboot, and remove VMs, as well as view the current status of all VMs. 99 | 100 | 101 | ### Build for run 102 | 1. Build the `vvmanager` executable: 103 | 104 | ```sh 105 | go build -o vvmanager main.go 106 | ``` 107 | 108 | ### Usage 109 | 110 | The `webconsole.sh` script is used to manage the web console server. It supports `start`, `stop`, `restart`, and `run` commands. 111 | 112 | - `start`: Starts the web console server in the background and rotates logs daily. 113 | - `stop`: Stops the running web console server. 114 | - `restart`: Restarts the web console server. 115 | - `run`: Runs the web console server in the foreground. 116 | 117 | To use the script, run the following commands: 118 | 119 | 1. Make the script executable: 120 | 121 | ```sh 122 | chmod +x webconsole.sh 123 | ``` 124 | 125 | 2. Start the web console server: 126 | 127 | ```sh 128 | ./webconsole.sh start 129 | ``` 130 | 131 | 3. Stop the web console server: 132 | 133 | ```sh 134 | ./webconsole.sh stop 135 | ``` 136 | 137 | 4. Restart the web console server: 138 | 139 | ```sh 140 | ./webconsole.sh restart 141 | ``` 142 | 143 | 5. Run the web console server in the foreground: 144 | 145 | ```sh 146 | ./webconsole.sh run 147 | ``` 148 | 149 | ### Configuration 150 | 151 | The `webconsole.sh` script handles log rotation and maintains a PID file to manage the server process. Logs are rotated daily, with a maximum of 4 log files retained (`history.log`, `history.log.1`, `history.log.2`, and `history.log.3`). 152 | 153 | ### Example 154 | 155 | Here is an example session using the `webconsole.sh` script: 156 | 157 | 1. Start the server: 158 | 159 | ```sh 160 | ./webconsole.sh start 161 | ``` 162 | 163 | 2. Access the web console by navigating to `http://:8080` in your web browser. 164 | 165 | 3. Stop the server: 166 | 167 | ```sh 168 | ./webconsole.sh stop 169 | ``` 170 | 171 | 4. Restart the server: 172 | 173 | ```sh 174 | ./webconsole.sh restart 175 | ``` 176 | 177 | ## Troubleshooting 178 | 179 | - Ensure all dependencies are installed and properly configured. 180 | - Check the log files (`history.log`) for any errors or warnings. 181 | - If the server does not start, verify that no other process is using port 8080. 182 | 183 | ## License 184 | 185 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 186 | 187 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | 5 | Vagrant.configure("2") do |config| 6 | config.vm.synced_folder "~/.ssh/", "/tmp/conf.d/" 7 | config.vm.provision "shell", path: "./provisioning/docker.sh", args: "" 8 | 9 | ## Docker VM cluster 10 | (1..9).each do |i| 11 | node_id = "docker0#{i}.dev" 12 | config.vm.define node_id do |node| 13 | node.vm.box = "ubuntu/focal64" 14 | node.vm.hostname = "#{node_id}" 15 | # node.vm.network "forwarded_port", guest: 8080, host: 808#{i}, host_ip: "127.0.0.1" 16 | node.vm.network "private_network", ip: "192.168.62.10#{i}", netmask: "255.255.255.0" 17 | # node.vm.synced_folder "./data", "/vagrant_data" 18 | node.vm.provider "virtualbox" do |vb| 19 | vb.memory = "4096" 20 | vb.cpus = "2" 21 | end 22 | end 23 | end 24 | 25 | ## Test VM cluster 26 | (1..9).each do |i| 27 | node_id = "test0#{i}.dev" 28 | config.vm.define node_id do |node| 29 | node.vm.box = "ubuntu/focal64" 30 | node.vm.hostname = "#{node_id}" 31 | # node.vm.network "forwarded_port", guest: 8080, host: 808#{i}, host_ip: "127.0.0.1" 32 | node.vm.network "private_network", ip: "192.168.62.20#{i}", netmask: "255.255.255.0" 33 | # node.vm.synced_folder "./data", "/vagrant_data" 34 | node.vm.provider "virtualbox" do |vb| 35 | vb.memory = "1024" 36 | vb.cpus = "1" 37 | end 38 | end 39 | end 40 | 41 | ## Win VM cluster 42 | (1..9).each do |i| 43 | node_id = "win0#{i}.dev" 44 | config.vm.define node_id do |node| 45 | config.vm.provision "shell", path: "./provisioning/provision.ps1", args: "" 46 | config.vm.synced_folder "./windows_storege", "c:\\tmp" 47 | node.vm.box = "gusztavvargadr/windows-10" 48 | node.vm.hostname = "#{node_id}" 49 | #node.vm.network "forwarded_port", guest: "3389", host: "338#{i}", host_ip: "127.0.0.1" 50 | node.vm.network "forwarded_port", guest: "3389", host: "338#{i}", host_ip: "0.0.0.0" 51 | node.vm.network "private_network", ip: "192.168.62.21#{i}", netmask: "255.255.255.0" 52 | #node.vm.synced_folder "./data", "/vagrant_data" 53 | node.vm.provider "virtualbox" do |vb| 54 | vb.memory = "8196" 55 | vb.cpus = "4" 56 | vb.customize ['setextradata', :id, 'GUI/LastGuestSizeHint', '1280x720'] # 해상도 설정 추가 57 | end 58 | end 59 | end 60 | 61 | 62 | # Win Server VM cluster 63 | (1..2).each do |i| 64 | node_id = "winserver0#{i}.dev" 65 | config.vm.define node_id do |node| 66 | config.vm.provision "shell", path: "./provisioning/provision.ps1", args: "" 67 | config.vm.synced_folder "./windows_storege", "c:\\tmp" 68 | node.vm.box = "StefanScherer/windows_2019" 69 | node.vm.hostname = "#{node_id}" 70 | #node.vm.network "forwarded_port", guest: "3389", host: "338#{i}", host_ip: "127.0.0.1" 71 | node.vm.network "forwarded_port", guest: "3389", host: "339#{i}", host_ip: "0.0.0.0" 72 | node.vm.network "forwarded_port", guest: "1433", host: "143#{i}", host_ip: "0.0.0.0" 73 | node.vm.network "private_network", ip: "192.168.62.22#{i}", netmask: "255.255.255.0" 74 | #node.vm.synced_folder "./data", "/vagrant_data" 75 | node.vm.provider "virtualbox" do |vb| 76 | vb.memory = "16384" 77 | vb.cpus = "4" 78 | vb.customize ['setextradata', :id, 'GUI/LastGuestSizeHint', '1280x720'] # 해상도 설정 추가 79 | end 80 | end 81 | end 82 | 83 | 84 | config.vm.provider "virtualbox" do |vb| 85 | vb.memory = "2048" 86 | config.vm.provider "virtualbox" do |vb| 87 | vb.memory = "2048" 88 | vb.cpus = "2" 89 | ## Display the VirtualBox GUI when booting the machine 90 | #vb.gui = true 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /Vagrantfile01: -------------------------------------------------------------------------------- 1 | # vagrant plugin install vagrant-disksize 2 | # vagrant plugin install vagrant-vbguest 3 | # 4 | 5 | VAGRANTFILE_API_VERSION = "2" 6 | NODE_COUNT = 2 7 | 8 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 9 | # All Vagrant configuration is done here. The most common configuration 10 | # options are documented and commented below. For a complete reference, 11 | # please see the online documentation at vagrantup.com. 12 | 13 | # Every Vagrant virtual environment requires a box to build off of. 14 | # See box list 15 | # http://www.vagrantbox.es/ 16 | 17 | config.vm.box = "centos/6" 18 | config.disksize.size = '50GB' 19 | 20 | NODE_COUNT.times do |i| 21 | node_id = "docker0#{i}.dev" 22 | config.vm.define node_id do |node| 23 | node.vm.hostname = "#{node_id}" 24 | 25 | 26 | # The url from where the 'config.vm.box' box will be fetched if it 27 | # doesn't already exist on the user's system. 28 | # config.vm.box_url = "http://domain.com/path/to/above.box" 29 | 30 | # Create a forwarded port mapping which allows access to a specific port 31 | # within the machine from a port on the host machine. In the example below, 32 | # accessing "localhost:8080" will access port 80 on the guest machine. 33 | node.vm.network "forwarded_port", guest: 1426, host: "1426#{i}" 34 | node.vm.network "forwarded_port", guest: 1427, host: "1427#{i}" 35 | 36 | # Create a private network, which allows host-only access to the machine 37 | # using a specific IP. 38 | # config.vm.network "private_network", ip: "192.168.33.10" 39 | node.vm.network :private_network, ip: "192.168.58.1#{i}" 40 | 41 | # Create a public network, which generally matched to bridged network. 42 | # Bridged networks make the machine appear as another physical device on 43 | # your network. 44 | # config.vm.network "public_network" 45 | 46 | # If true, then any SSH connections made will enable agent forwarding. 47 | # Default value: false 48 | # config.ssh.forward_agent = true 49 | end 50 | end 51 | 52 | # Share an additional folder to the guest VM. The first argument is 53 | # the path on the host to the actual folder. The second argument is 54 | # the path on the guest to mount the folder. And the optional third 55 | # argument is a set of non-required options. 56 | config.vm.synced_folder "../incubator-pinot", "/incubator-pinot" 57 | config.vm.synced_folder "../data", "/vagrant-data" 58 | 59 | # Provider-specific configuration so you can fine-tune various 60 | # backing providers for Vagrant. These expose provider-specific options. 61 | # Example for VirtualBox: 62 | # 63 | # config.vm.provider "virtualbox" do |vb| 64 | # # Don't boot with headless mode 65 | # vb.gui = true 66 | # 67 | # # Use VBoxManage to customize the VM. For example to change memory: 68 | # vb.customize ["modifyvm", :id, "--memory", "1024"] 69 | # end 70 | config.vm.provider :virtualbox do |vb| 71 | # Don't boot with headless mode 72 | # vb.gui = true 73 | 74 | # Enable creating symlinks between guest and host 75 | #vb.customize [ 76 | # see https://github.com/mitchellh/vagrant/issues/713#issuecomment-17296765 77 | # 1) Added these lines to my config : 78 | # 79 | # 2) run this command in an admin command prompt on windows : 80 | # >> fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1 81 | # see http://technet.microsoft.com/ja-jp/library/cc785435%28v=ws.10%29.aspx 82 | # 3) REBOOT HOST MACHINE 83 | # 4) 'vagrant up' from an admin command prompt 84 | # "setextradata", :id, 85 | # "VBoxInternal2/SharedFoldersEnableSymlinksCreate/vagrant-root", "1" 86 | #] 87 | 88 | # Use VBoxManage to customize the VM. For example to change memory: 89 | vb.customize [ 90 | 'modifyvm', :id, 91 | '--natdnshostresolver1', 'on', 92 | '--memory', '3072', 93 | '--cpus', '2' 94 | ] 95 | end 96 | 97 | # 98 | # View the documentation for the provider you're using for more 99 | # information on available options. 100 | 101 | # Enable provisioning with Puppet stand alone. Puppet manifests 102 | # are contained in a directory path relative to this Vagrantfile. 103 | # You will need to create the manifests directory and a manifest in 104 | # the file centos65.pp in the manifests_path directory. 105 | # 106 | # An example Puppet manifest to provision the message of the day: 107 | # 108 | # # group { "puppet": 109 | # # ensure => "present", 110 | # # } 111 | # # 112 | # # File { owner => 0, group => 0, mode => 0644 } 113 | # # 114 | # # file { '/etc/motd': 115 | # # content => "Welcome to your Vagrant-built virtual machine! 116 | # # Managed by Puppet.\n" 117 | # # } 118 | # 119 | # config.vm.provision "puppet" do |puppet| 120 | # puppet.manifests_path = "manifests" 121 | # puppet.manifest_file = "site.pp" 122 | # end 123 | 124 | # Enable provisioning with chef solo, specifying a cookbooks path, roles 125 | # path, and data_bags path (all relative to this Vagrantfile), and adding 126 | # some recipes and/or roles. 127 | # 128 | # config.vm.provision "chef_solo" do |chef| 129 | # chef.cookbooks_path = "../my-recipes/cookbooks" 130 | # chef.roles_path = "../my-recipes/roles" 131 | # chef.data_bags_path = "../my-recipes/data_bags" 132 | # chef.add_recipe "mysql" 133 | # chef.add_role "web" 134 | # 135 | # # You may also specify custom JSON attributes: 136 | # chef.json = { :mysql_password => "foo" } 137 | # end 138 | 139 | # Enable provisioning with chef server, specifying the chef server URL, 140 | # and the path to the validation key (relative to this Vagrantfile). 141 | # 142 | # The Opscode Platform uses HTTPS. Substitute your organization for 143 | # ORGNAME in the URL and validation key. 144 | # 145 | # If you have your own Chef Server, use the appropriate URL, which may be 146 | # HTTP instead of HTTPS depending on your configuration. Also change the 147 | # validation key to validation.pem. 148 | # 149 | # config.vm.provision "chef_client" do |chef| 150 | # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" 151 | # chef.validation_key_path = "ORGNAME-validator.pem" 152 | # end 153 | # 154 | # If you're using the Opscode platform, your validator client is 155 | # ORGNAME-validator, replacing ORGNAME with your organization name. 156 | # 157 | # If you have your own Chef Server, the default validation client name is 158 | # chef-validator, unless you changed the configuration. 159 | # 160 | # chef.validation_client_name = "ORGNAME-validator" 161 | end 162 | -------------------------------------------------------------------------------- /Vagrantfile_1604: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing.a 8 | 9 | ######## VirtualBox Box image name 10 | OS_NAME="folimy/Ubuntu1604_with_docker" 11 | OS_URL="https://app.vagrantup.com/folimy/boxes/Ubuntu1604_with_docker/versions/0.1.1/providers/virtualbox.box" 12 | #OS_NAME="ubuntu1604" 13 | #OS_URL="https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-vagrant.box" 14 | 15 | VAGRANTFILE_API_VERSION = "2" 16 | NODE_COUNT = 10 17 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 18 | config.vm.provision "shell", path: "./provisioning/default_setting.sh", args: "" 19 | config.vm.synced_folder "~/.ssh/", "/tmp/conf.d/" 20 | ## For Docker instance 21 | NODE_COUNT.times do |i| 22 | node_id = "docker0#{i}.dev" 23 | config.vm.define node_id do |node| 24 | ### Args= [service name] [master / slave] [master IP] [advertise IP] 25 | config.vm.provision "shell", path: "./provisioning/docker.sh", args: "" 26 | # config.vm.network "forwarded_port", guest: 5601, host: 5601 27 | # config.vm.network "forwarded_port", guest: 5000, host: 5000 28 | # config.vm.network "forwarded_port", guest: 9200, host: 9200 29 | config.vm.network "private_network", ip: "192.168.10.1#{i}" 30 | # config.vm.network "public_network", :dev => "br0", :mode => "bridge", :type => "bridge", :ip => "192.168.133.10#{i}", :netmask => "255.255.255.0", :auto_config => "false" 31 | node.vm.box = OS_NAME 32 | node.vm.box_url = OS_URL 33 | node.vm.hostname = "#{node_id}" 34 | end 35 | end 36 | 37 | config.vm.provider :virtualbox do |vb| 38 | vb.customize ["modifyvm", :id, "--memory", "4096"] 39 | vb.customize ["modifyvm", :id, "--cpus", "2"] 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /Vagrantfile_20240226: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.synced_folder "~/.ssh/", "/tmp/conf.d/" 6 | config.vm.provision "shell", path: "./provisioning/docker.sh", args: "" 7 | 8 | ## Docker VM cluster 9 | (1..9).each do |i| 10 | node_id = "docker0#{i}.dev" 11 | config.vm.define node_id do |node| 12 | node.vm.box = "ubuntu/focal64" 13 | node.vm.hostname = "#{node_id}" 14 | # node.vm.network "forwarded_port", guest: 8080, host: 808#{i}, host_ip: "127.0.0.1" 15 | node.vm.network "private_network", ip: "192.168.62.10#{i}", netmask: "255.255.255.0" 16 | # node.vm.synced_folder "./data", "/vagrant_data" 17 | node.vm.provider "virtualbox" do |vb| 18 | vb.memory = "4096" 19 | vb.cpus = "2" 20 | end 21 | end 22 | end 23 | 24 | ## Test VM cluster 25 | (1..9).each do |i| 26 | node_id = "test0#{i}.dev" 27 | config.vm.define node_id do |node| 28 | node.vm.box = "ubuntu/focal64" 29 | node.vm.hostname = "#{node_id}" 30 | # node.vm.network "forwarded_port", guest: 8080, host: 808#{i}, host_ip: "127.0.0.1" 31 | node.vm.network "private_network", ip: "192.168.62.20#{i}", netmask: "255.255.255.0" 32 | # node.vm.synced_folder "./data", "/vagrant_data" 33 | node.vm.provider "virtualbox" do |vb| 34 | vb.memory = "1024" 35 | vb.cpus = "1" 36 | end 37 | end 38 | end 39 | 40 | ## Win VM cluster 41 | (1..9).each do |i| 42 | node_id = "win0#{i}.dev" 43 | config.vm.define node_id do |node| 44 | config.vm.provision "shell", path: "./provisioning/provision.ps1", args: "" 45 | config.vm.synced_folder "./windows_storege", "c:\tmp" 46 | node.vm.box = "gusztavvargadr/windows-10" 47 | node.vm.hostname = "#{node_id}" 48 | #node.vm.network "forwarded_port", guest: "3389", host: "338#{i}", host_ip: "127.0.0.1" 49 | node.vm.network "forwarded_port", guest: "3389", host: "338#{i}", host_ip: "0.0.0.0" 50 | node.vm.network "private_network", ip: "192.168.62.21#{i}", netmask: "255.255.255.0" 51 | # node.vm.synced_folder "./data", "/vagrant_data" 52 | node.vm.provider "virtualbox" do |vb| 53 | vb.memory = "8196" 54 | vb.cpus = "4" 55 | end 56 | end 57 | end 58 | 59 | 60 | config.vm.provider "virtualbox" do |vb| 61 | vb.memory = "2048" 62 | vb.cpus = "2" 63 | ## Display the VirtualBox GUI when booting the machine 64 | #vb.gui = true 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /Vagrantfile_back: -------------------------------------------------------------------------------- 1 | OS_NAME="ubuntu/focal64" 2 | NODE_COUNT = 10 3 | 4 | Vagrant.configure("2") do |config| 5 | NODE_COUNT.times do |i| 6 | node_id = "docker0#{i}.dev" 7 | config.vm.define node_id do |node| 8 | config.hostmanager.enabled = true 9 | config.hostmanager.manage_host = true 10 | config.vm.synced_folder "~/.ssh/", "/tmp/conf.d/" 11 | config.vm.provision "shell", path: "./provisioning/docker.sh", args: "" 12 | config.vm.network "private_network", ip: "192.168.62.10#{i}", netmask: "255.255.255.0" 13 | node.vm.box = OS_NAME 14 | #node.vm.hostname = "#{node_id}" 15 | node.vm.hostname = "docker01.dev" 16 | end 17 | end 18 | 19 | config.vm.provider "virtualbox" do |vb| 20 | vb.memory = "2048" 21 | vb.cpus = "2" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /advisor/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | cadvisor: 4 | image: google/cadvisor 5 | volumes: 6 | - "/:/rootfs:ro" 7 | - "/var/run:/var/run:rw" 8 | - "/sys:/sys:ro" 9 | - "/var/lib/docker/:/var/lib/docker:ro" 10 | ports: 11 | - 8080:8080 12 | -------------------------------------------------------------------------------- /ctl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Code from https://github.com/ralfyang/vagrant_docker_cluster. Powered by Github. 3 | 4 | hname=$1 5 | Vagrant_version="2.3.4" 6 | 7 | if [[ $hname = "" ]];then 8 | hname="docker01.dev" 9 | fi 10 | 11 | sshkey_check(){ 12 | if [[ ! -f $HOME/.ssh/id_rsa ]];then 13 | ssh-keygen -f $HOME/.ssh/id_rsa -t rsa -N '' 14 | fi 15 | return 0 16 | } 17 | 18 | resource_chk="./resource.status" 19 | if [[ ! -f $resource_chk ]];then 20 | touch $resource_chk 21 | fi 22 | 23 | start(){ 24 | sshkey_check 25 | vagrant up $hname 26 | result_vm 27 | vagrant ssh $hname 28 | } 29 | 30 | stop(){ 31 | vagrant halt $hname 32 | result_vm 33 | } 34 | 35 | connection(){ 36 | vagrant ssh $hname 37 | } 38 | 39 | reload(){ 40 | vagrant reload $hname 41 | result_vm 42 | } 43 | 44 | result_vm(){ 45 | $(vagrant status | sed '$d' | sed '$d' |sed '1,2d' |sed '$d' |sed '$d' > $resource_chk ) & 46 | } 47 | 48 | status(){ 49 | clear 50 | cat $resource_chk 51 | } 52 | 53 | reboot(){ 54 | vagrant halt $hname 55 | vagrant up $hname 56 | result_vm 57 | } 58 | 59 | remove(){ 60 | echo " Are sure that remove the Virtual machine ? [ y ]" 61 | read sure 62 | if [[ $sure = "y" ]];then 63 | vagrant destroy -f $hname 64 | fi 65 | result_vm 66 | } 67 | 68 | application_install(){ 69 | mkdir -p ~/tmp 70 | cd ~/tmp 71 | arch=`uname -s`-`uname -m` 72 | os=`uname -s` 73 | 74 | case $os in 75 | Linux) 76 | ## VirtualBox install 77 | sudo apt-add-repository "deb http://download.virtualbox.org/virtualbox/debian $(lsb_release -sc) contrib" 78 | #wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add - 79 | #wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add - 80 | curl https://www.virtualbox.org/download/oracle_vbox_2016.asc -o /tmp/virtualbox.key 81 | sudo apt-key add /tmp/virtualbox.key 82 | sudo apt-get update 83 | sudo apt-get install linux-headers-$(uname -r) 84 | sudo apt-get install virtualbox -y 85 | sudo /sbin/vboxconfig 86 | 87 | ## Vagrant install 88 | wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg 89 | echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list 90 | sudo apt update && sudo apt install vagrant 91 | ;; 92 | 93 | Darwin) 94 | ## VirtualBox Download & Install 95 | VirtualBox_installer="https://download.virtualbox.org/virtualbox/7.0.6/VirtualBox-7.0.6-155176-OSX.dmg" 96 | VirtualBox_Ext_pkg="https://download.virtualbox.org/virtualbox/7.0.6/Oracle_VM_VirtualBox_Extension_Pack-7.0.6.vbox-extpack" 97 | VirtualBox_file=$(echo "$VirtualBox_installer" | awk -F'/' '{print $NF}') 98 | curl -L $VirtualBox_installer -o ./$VirtualBox_file 99 | curl -L $VirtualBox_Ext_pkg -o Oracle_VM_VirtualBox_Extension_Pack.vbox-extpack 100 | sudo hdiutil attach $VirtualBox_file 101 | sudo installer -pkg /Volumes/VirtualBox/VirtualBox.pkg -target / 102 | hdiutil unmount /Volumes/VirtualBox/ 103 | sudo vboxmanage extpack install ./Oracle_VM_VirtualBox_Extension_Pack.vbox-extpack 104 | rm -f ./$VirtualBox_file 105 | 106 | ## Vagrant Download & Install 107 | Vagrant_installer="https://releases.hashicorp.com/vagrant/$Vagrant_version/vagrant_${Vagrant_version}_darwin_amd64.dmg" 108 | #Vagrant_file=$(echo "$Vagrant_installer" | awk -F'/' '{print $NF}') 109 | Vagrant_file="vagrant_install.dmg" 110 | curl -L $Vagrant_installer -o ./$Vagrant_file 111 | sudo hdiutil attach $Vagrant_file 112 | sudo installer -pkg /Volumes/Vagrant/vagrant.pkg -target / 113 | hdiutil unmount /Volumes/Vagrant 114 | rm -f ./$Vagrant_installer 115 | ;; 116 | esac 117 | 118 | 119 | } 120 | 121 | clear 122 | BARR="===========================================================" 123 | echo "$BARR" 124 | echo " What do you want ?" 125 | echo "$BARR" 126 | echo "[0] Install the Virtualbox & Vagrant" 127 | echo "[1] Start VM & login" 128 | echo "[2] Login to VM" 129 | echo "[3] Stop VM" 130 | echo "[4] Reload VM" 131 | echo "[5] Reboot VM" 132 | echo "[RM] Remove VM" 133 | echo "[s] VM status" 134 | echo "$BARR" 135 | echo -n " Please insert a key as you need = " 136 | read choice 137 | echo "$BARR" 138 | 139 | case $choice in 140 | 0) 141 | application_install;; 142 | 1) 143 | start;; 144 | 2) 145 | connection;; 146 | 3) 147 | stop;; 148 | 4) 149 | reload;; 150 | 5) 151 | reboot;; 152 | RM|rm) 153 | remove;; 154 | S|s) 155 | status;; 156 | esac 157 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module vagrant-api 2 | 3 | go 1.22.3 4 | 5 | require ( 6 | github.com/felixge/httpsnoop v1.0.3 // indirect 7 | github.com/go-ole/go-ole v1.2.6 // indirect 8 | github.com/gorilla/handlers v1.5.2 // indirect 9 | github.com/gorilla/mux v1.8.1 // indirect 10 | github.com/gorilla/websocket v1.5.1 // indirect 11 | github.com/joho/godotenv v1.5.1 // indirect 12 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect 13 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 14 | golang.org/x/net v0.17.0 // indirect 15 | golang.org/x/sys v0.13.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= 2 | github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 3 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 4 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 5 | github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= 6 | github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= 7 | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= 8 | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 9 | github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= 10 | github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= 11 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 12 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 13 | github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= 14 | github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 15 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= 16 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 17 | golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= 18 | golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 19 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 20 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= 21 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 22 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "fmt" 7 | "log" 8 | "net/http" 9 | "os" 10 | "os/exec" 11 | "regexp" 12 | "strconv" 13 | "strings" 14 | "syscall" 15 | 16 | "github.com/gorilla/websocket" 17 | "github.com/joho/godotenv" 18 | ) 19 | 20 | type CommandRequest struct { 21 | Command string `json:"command"` 22 | Arg string `json:"arg"` 23 | Password string `json:"password"` 24 | } 25 | 26 | type VMStatus struct { 27 | Name string `json:"Name"` 28 | State string `json:"State"` 29 | IP string `json:"IP"` 30 | Port string `json:"Port"` 31 | Provider string `json:"Provider"` 32 | } 33 | 34 | type IPInfo struct { 35 | PublicIP string `json:"publicIP"` 36 | PrivateIP string `json:"privateIP"` 37 | } 38 | 39 | type MemoryInfo struct { 40 | AvailableMemory string `json:"availableMemory"` 41 | TotalMemory string `json:"totalMemory"` 42 | } 43 | 44 | var upgrader = websocket.Upgrader{ 45 | ReadBufferSize: 1024, 46 | WriteBufferSize: 1024, 47 | } 48 | 49 | var logClients = make(map[*websocket.Conn]bool) 50 | 51 | func loadEnv() { 52 | err := godotenv.Load(".env") 53 | if err != nil { 54 | log.Printf("Error loading .env file: %v", err) 55 | } else { 56 | log.Println(".env file successfully loaded") 57 | } 58 | } 59 | 60 | func getEnv(key, fallback string) string { 61 | value, exists := os.LookupEnv(key) 62 | if !exists { 63 | return fallback 64 | } 65 | return value 66 | } 67 | 68 | func getPort() string { 69 | return getEnv("PORT", "8080") // 기본 포트는 8080으로 설정 70 | } 71 | 72 | func getPublicIP() string { 73 | return getEnv("Public_IP", "Unavailable") 74 | } 75 | 76 | func getPrivateIP() string { 77 | return getEnv("Private_IP", "Unavailable") 78 | } 79 | 80 | func getPassword() string { 81 | return getEnv("PASSWORD", "defaultpassword") 82 | } 83 | 84 | func authenticate(password string) bool { 85 | return password == getPassword() 86 | } 87 | 88 | func executeCommand(w http.ResponseWriter, r *http.Request) { 89 | var req CommandRequest 90 | if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 91 | http.Error(w, "Invalid request", http.StatusBadRequest) 92 | return 93 | } 94 | 95 | if !authenticate(req.Password) { 96 | http.Error(w, "Unauthorized", http.StatusUnauthorized) 97 | return 98 | } 99 | 100 | log.Printf("Received command: %s, Arg: %s\n", req.Command, req.Arg) 101 | 102 | var cmd *exec.Cmd 103 | switch req.Command { 104 | case "status": 105 | cmd = exec.Command("vagrant", "status", "--machine-readable") 106 | case "start": 107 | cmd = exec.Command("vagrant", "up", req.Arg) 108 | case "stop": 109 | cmd = exec.Command("vagrant", "halt", req.Arg) 110 | case "reload": 111 | cmd = exec.Command("vagrant", "reload", req.Arg) 112 | case "reboot": 113 | cmd = exec.Command("vagrant", "halt", req.Arg) 114 | if err := cmd.Run(); err != nil { 115 | log.Printf("Command error: %s\n", err) 116 | http.Error(w, "Command execution failed", http.StatusInternalServerError) 117 | return 118 | } 119 | cmd = exec.Command("vagrant", "up", req.Arg) 120 | case "remove": 121 | cmd = exec.Command("vagrant", "destroy", "-f", req.Arg) 122 | default: 123 | http.Error(w, "Unknown command", http.StatusBadRequest) 124 | return 125 | } 126 | 127 | if cmd == nil { 128 | http.Error(w, "Unknown command", http.StatusBadRequest) 129 | return 130 | } 131 | 132 | outputPipe, err := cmd.StdoutPipe() 133 | if err != nil { 134 | log.Printf("Error getting stdout pipe: %s\n", err) 135 | http.Error(w, "Error executing command", http.StatusInternalServerError) 136 | return 137 | } 138 | 139 | if err := cmd.Start(); err != nil { 140 | log.Printf("Error starting command: %s\n", err) 141 | http.Error(w, "Error executing command", http.StatusInternalServerError) 142 | return 143 | } 144 | 145 | go func() { 146 | scanner := bufio.NewScanner(outputPipe) 147 | for scanner.Scan() { 148 | line := scanner.Text() 149 | log.Printf("Output: %s\n", line) 150 | for client := range logClients { 151 | err := client.WriteMessage(websocket.TextMessage, []byte(line)) 152 | if err != nil { 153 | log.Printf("Error writing to websocket client: %s\n", err) 154 | client.Close() 155 | delete(logClients, client) 156 | } 157 | } 158 | } 159 | }() 160 | 161 | if err := cmd.Wait(); err != nil { 162 | log.Printf("Command error: %s\n", err) 163 | http.Error(w, "Command execution failed", http.StatusInternalServerError) 164 | return 165 | } 166 | 167 | var vmStatuses []VMStatus 168 | if req.Command == "status" { 169 | vmStatuses, err = parseVagrantStatus() 170 | if err != nil { 171 | log.Printf("Error parsing vagrant status: %s\n", err) 172 | http.Error(w, "Error parsing status", http.StatusInternalServerError) 173 | return 174 | } 175 | } 176 | 177 | resp, err := json.Marshal(map[string]interface{}{"status": vmStatuses}) 178 | if err != nil { 179 | http.Error(w, "Failed to marshal response", http.StatusInternalServerError) 180 | return 181 | } 182 | 183 | w.Header().Set("Content-Type", "application/json") 184 | w.Write(resp) 185 | } 186 | 187 | func parseVagrantStatus() ([]VMStatus, error) { 188 | cmd := exec.Command("vagrant", "status", "--machine-readable") 189 | output, err := cmd.CombinedOutput() 190 | if err != nil { 191 | return nil, err 192 | } 193 | 194 | lines := strings.Split(string(output), "\n") 195 | var statuses []VMStatus 196 | ipMap, portMap, err := getVMIpPortMapping() 197 | if err != nil { 198 | return nil, err 199 | } 200 | for _, line := range lines { 201 | fields := strings.Split(line, ",") 202 | if len(fields) >= 4 && fields[2] == "state" { 203 | ip := ipMap[fields[1]] 204 | port := portMap[fields[1]] 205 | status := VMStatus{ 206 | Name: fields[1], 207 | State: fields[3], 208 | IP: ip, 209 | Port: port, 210 | Provider: fields[2], 211 | } 212 | statuses = append(statuses, status) 213 | } 214 | } 215 | 216 | return statuses, nil 217 | } 218 | 219 | func getVMIpPortMapping() (map[string]string, map[string]string, error) { 220 | file, err := os.Open("Vagrantfile") 221 | if err != nil { 222 | return nil, nil, err 223 | } 224 | defer file.Close() 225 | 226 | ipMap := make(map[string]string) 227 | portMap := make(map[string]string) 228 | scanner := bufio.NewScanner(file) 229 | ipRegex := regexp.MustCompile(`ip:\s*"([^"]+)"`) 230 | portRegex := regexp.MustCompile(`host:\s*"([^"]+)"`) 231 | nameRegex := regexp.MustCompile(`node_id\s*=\s*"([^"]+)"`) 232 | 233 | var currentName string 234 | for scanner.Scan() { 235 | line := scanner.Text() 236 | if matches := nameRegex.FindStringSubmatch(line); matches != nil { 237 | currentName = matches[1] 238 | } else if matches := ipRegex.FindStringSubmatch(line); matches != nil { 239 | ipMap[currentName] = matches[1] 240 | } else if matches := portRegex.FindStringSubmatch(line); matches != nil { 241 | portMap[currentName] = matches[1] 242 | } 243 | } 244 | 245 | if err := scanner.Err(); err != nil { 246 | return nil, nil, err 247 | } 248 | 249 | return ipMap, portMap, nil 250 | } 251 | 252 | func getIPInfo(w http.ResponseWriter, r *http.Request) { 253 | publicIP := getPublicIP() 254 | privateIP := getPrivateIP() 255 | 256 | resp, err := json.Marshal(IPInfo{ 257 | PublicIP: publicIP, 258 | PrivateIP: privateIP, 259 | }) 260 | if err != nil { 261 | http.Error(w, "Failed to marshal IP info", http.StatusInternalServerError) 262 | return 263 | } 264 | 265 | w.Header().Set("Content-Type", "application/json") 266 | w.Write(resp) 267 | } 268 | 269 | func getMemoryInfo(w http.ResponseWriter, r *http.Request) { 270 | cmd := exec.Command("free", "-h") 271 | output, err := cmd.Output() 272 | if err != nil { 273 | http.Error(w, "Failed to get memory info", http.StatusInternalServerError) 274 | return 275 | } 276 | 277 | lines := strings.Split(string(output), "\n") 278 | if len(lines) < 2 { 279 | http.Error(w, "Failed to parse memory info", http.StatusInternalServerError) 280 | return 281 | } 282 | 283 | fields := strings.Fields(lines[1]) 284 | if len(fields) < 7 { 285 | http.Error(w, "Failed to parse memory info", http.StatusInternalServerError) 286 | return 287 | } 288 | 289 | totalMemory := fields[1] 290 | availableMemory := fields[6] 291 | 292 | resp, err := json.Marshal(MemoryInfo{ 293 | AvailableMemory: availableMemory, 294 | TotalMemory: totalMemory, 295 | }) 296 | if err != nil { 297 | http.Error(w, "Failed to marshal memory info", http.StatusInternalServerError) 298 | return 299 | } 300 | 301 | w.Header().Set("Content-Type", "application/json") 302 | w.Write(resp) 303 | } 304 | 305 | func logHandler(w http.ResponseWriter, r *http.Request) { 306 | ws, err := upgrader.Upgrade(w, r, nil) 307 | if err != nil { 308 | log.Printf("Failed to set websocket upgrade: %s\n", err) 309 | return 310 | } 311 | logClients[ws] = true 312 | 313 | defer func() { 314 | delete(logClients, ws) 315 | ws.Close() 316 | }() 317 | 318 | for { 319 | _, _, err := ws.ReadMessage() 320 | if err != nil { 321 | log.Printf("WebSocket read error: %s\n", err) 322 | break 323 | } 324 | } 325 | } 326 | 327 | func configHandler(w http.ResponseWriter, r *http.Request) { 328 | config, err := os.ReadFile("Vagrantfile") 329 | if err != nil { 330 | http.Error(w, "Failed to read config", http.StatusInternalServerError) 331 | return 332 | } 333 | 334 | resp, err := json.Marshal(map[string]interface{}{"config": string(config)}) 335 | if err != nil { 336 | http.Error(w, "Failed to marshal config", http.StatusInternalServerError) 337 | return 338 | } 339 | 340 | w.Header().Set("Content-Type", "application/json") 341 | w.Write(resp) 342 | } 343 | 344 | func mainStop() error { 345 | pidFile := "vvmanager.pid" 346 | pidData, err := os.ReadFile(pidFile) 347 | if err != nil { 348 | return fmt.Errorf("failed to read pid file: %v", err) 349 | } 350 | 351 | pid, err := strconv.Atoi(strings.TrimSpace(string(pidData))) 352 | if err != nil { 353 | return fmt.Errorf("failed to parse pid: %v", err) 354 | } 355 | 356 | if err := syscall.Kill(pid, syscall.SIGTERM); err != nil { 357 | return fmt.Errorf("failed to kill process: %v", err) 358 | } 359 | 360 | if err := os.Remove(pidFile); err != nil { 361 | return fmt.Errorf("failed to remove pid file: %v", err) 362 | } 363 | 364 | return nil 365 | } 366 | 367 | func mainStart() error { 368 | cmd := exec.Command("./vvmanager", "run") 369 | cmd.Stdout = os.Stdout 370 | cmd.Stderr = os.Stderr 371 | cmd.Start() 372 | 373 | pidFile, err := os.Create("vvmanager.pid") 374 | if err != nil { 375 | return fmt.Errorf("failed to create pid file: %v", err) 376 | } 377 | defer pidFile.Close() 378 | 379 | if _, err := pidFile.WriteString(fmt.Sprintf("%d", cmd.Process.Pid)); err != nil { 380 | return fmt.Errorf("failed to write pid to file: %v", err) 381 | } 382 | 383 | return nil 384 | } 385 | 386 | func main() { 387 | if len(os.Args) > 1 { 388 | switch os.Args[1] { 389 | case "start": 390 | if err := mainStart(); err != nil { 391 | log.Fatalf("Failed to start: %v", err) 392 | } 393 | case "stop": 394 | if err := mainStop(); err != nil { 395 | log.Fatalf("Failed to stop: %v", err) 396 | } 397 | case "restart": 398 | if err := mainStop(); err != nil { 399 | log.Fatalf("Failed to stop: %v", err) 400 | } 401 | if err := mainStart(); err != nil { 402 | log.Fatalf("Failed to start: %v", err) 403 | } 404 | case "run": 405 | loadEnv() // .env 파일을 로드하여 환경 변수를 설정 406 | port := getPort() // .env에서 포트를 가져옴 407 | http.HandleFunc("/execute", executeCommand) 408 | http.HandleFunc("/ipinfo", getIPInfo) 409 | http.HandleFunc("/memoryinfo", getMemoryInfo) 410 | http.HandleFunc("/logs", logHandler) 411 | http.HandleFunc("/config", configHandler) 412 | 413 | // Serve static files from the "static" directory 414 | fs := http.FileServer(http.Dir("static")) 415 | http.Handle("/", fs) 416 | 417 | log.Printf("Starting server on :%s", port) // 포트 출력 418 | log.Fatal(http.ListenAndServe(":"+port, nil)) // 서버 시작 419 | default: 420 | log.Fatalf("Unknown command: %s", os.Args[1]) 421 | } 422 | } else { 423 | log.Println("Usage: vvmanager [start|stop|restart|run]") 424 | } 425 | } 426 | 427 | -------------------------------------------------------------------------------- /provisioning/docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | LANG=en_US.UTF-8 3 | #sed -i '/^LANG=/d' /etc/sysconfig/i18n 4 | #echo 'LANG=en_US.UTF-8' >> /etc/sysconfig/i18n 5 | #sed -i 's/=enforcing/=disabled/g' /etc/selinux/config 6 | 7 | #setenforce 0 8 | apt update 9 | apt-get install curl wget net-tools -y 10 | 11 | mkdir -p /root/.ssh 12 | cp -Rfv /tmp/conf.d/* /root/.ssh 13 | sudo -u vagrant echo "alias ll='ls -lia' " >> /home/vagrant/.bash_profile 14 | 15 | echo ">> Docker Install" 16 | curl -sL zxz.kr/docker|bash 17 | -------------------------------------------------------------------------------- /provisioning/docker.sh_bak: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Script for docker env. 3 | #sudo apt-get install libxslt-dev libxml2-dev libvirt-dev zlib1g-dev ruby-dev -y 4 | #vagrant box add ubuntu1404 http:// 5 | #vagrant plugin install vagrant-libvirt 6 | #vagrant plugin install vagrant-mutate 7 | 8 | sudo apt-get remove docker docker-engine 9 | sudo apt-get install \ 10 | linux-image-extra-$(uname -r) \ 11 | linux-image-extra-virtual 12 | 13 | sudo apt-get install \ 14 | apt-transport-https \ 15 | ca-certificates \ 16 | curl \ 17 | software-properties-common -y 18 | 19 | 20 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 21 | 22 | sudo apt-key fingerprint 0EBFCD88 23 | 24 | 25 | sudo add-apt-repository \ 26 | "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ 27 | $(lsb_release -cs) \ 28 | stable" 29 | 30 | 31 | sudo apt-get update 32 | 33 | sudo apt-get install docker-ce -y 34 | 35 | apt-cache madison docker-ce 36 | 37 | 38 | # Docker-compose install 39 | #curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/bin/docker-compose 40 | curl -L https://github.com/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` > /usr/bin/docker-compose 41 | chmod 755 /usr/bin/docker-compose 42 | 43 | 44 | Source="/data/source/" 45 | mkdir -p $Source 46 | 47 | # elk stack compose file download 48 | cd $Source 49 | 50 | 51 | ## Get the dcs from docker 52 | curl -sL bit.ly/ralf_dcs -o ./dcs 53 | sudo chmod 755 ./dcs 54 | sudo mv ./dcs /usr/bin/dcs 55 | 56 | 57 | 58 | ## Config for the ElasticSearch 59 | echo "vm.max_map_count=262144" >> /etc/sysctl.conf 60 | sysctl -w vm.max_map_count=262144 61 | -------------------------------------------------------------------------------- /provisioning/provision.ps1: -------------------------------------------------------------------------------- 1 | reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f 2 | netsh advfirewall firewall set rule group="remote desktop" new enable=Yes 3 | -------------------------------------------------------------------------------- /provisioning/useradd_perm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## function for user add & sudo permission 4 | User_add_comm(){ 5 | user=$1 6 | adduser $user 7 | usermod -aG sudo $user 8 | groups $user 9 | echo "$user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/$user 10 | } 11 | 12 | user_list=$1 13 | ## user_list empty check 14 | if [[ $user_list = "" ]];then 15 | echo "# " 16 | echo "# need a file of userlist" 17 | echo "# " 18 | exit 0 19 | fi 20 | 21 | 22 | ## For loop for each user 23 | users=`cat $user_list` 24 | for i in $users 25 | do 26 | echo "i = $i" 27 | User_add_comm $i 28 | done 29 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Vagrant Controller 5 | 74 | 75 | 76 |
77 |

Login

78 | 79 | 80 |
81 | 103 | 104 | 254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /static/script.js: -------------------------------------------------------------------------------- 1 | const socket = new WebSocket('ws://' + window.location.host + '/ws'); 2 | 3 | socket.onmessage = function(event) { 4 | const data = JSON.parse(event.data); 5 | if (data.error) { 6 | document.getElementById('output').innerText += 'Error: ' + data.error + '\n'; 7 | } else if (data.status) { 8 | displayVMStatus(data.status); 9 | } else if (data.output) { 10 | document.getElementById('output').innerText += data.output + '\n'; 11 | } 12 | }; 13 | 14 | socket.onclose = function(event) { 15 | document.getElementById('output').innerText += 'Connection closed.\n'; 16 | }; 17 | 18 | document.getElementById('refresh').addEventListener('click', function() { 19 | sendCommand('status', ''); 20 | }); 21 | 22 | function sendCommand(command, arg) { 23 | const message = { 24 | command: command, 25 | arg: arg 26 | }; 27 | document.getElementById('output').innerText = ''; 28 | socket.send(JSON.stringify(message)); 29 | } 30 | 31 | function displayVMStatus(statuses) { 32 | const tableBody = document.getElementById('vm-table-body'); 33 | tableBody.innerHTML = ''; 34 | statuses.forEach(status => { 35 | const row = document.createElement('tr'); 36 | row.innerHTML = ` 37 | ${status.Name} 38 | ${status.State} 39 | ${status.Port} 40 | ${getActions(status.State, status.Name)} 41 | `; 42 | tableBody.appendChild(row); 43 | }); 44 | } 45 | 46 | function getActions(state, name) { 47 | let actions = ''; 48 | if (state === 'running') { 49 | actions += ``; 50 | } else if (state === 'poweroff') { 51 | actions += ``; 52 | } else if (state === 'not_created') { 53 | actions += ``; 54 | } 55 | actions += ``; 56 | actions += ``; 57 | actions += ``; 58 | return actions; 59 | } 60 | 61 | window.onload = function() { 62 | fetch('/ipinfo') 63 | .then(response => response.json()) 64 | .then(data => { 65 | document.getElementById('public-ip').innerText = data.publicIP; 66 | document.getElementById('private-ip').innerText = data.privateIP; 67 | }); 68 | 69 | sendCommand('status', ''); 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial, sans-serif; 3 | margin: 20px; 4 | } 5 | 6 | h1 { 7 | font-size: 24px; 8 | } 9 | 10 | button { 11 | margin: 5px; 12 | padding: 10px 20px; 13 | font-size: 16px; 14 | } 15 | 16 | #output { 17 | margin-top: 20px; 18 | padding: 10px; 19 | border: 1px solid #ccc; 20 | height: 300px; 21 | overflow-y: auto; 22 | white-space: pre-wrap; 23 | } 24 | 25 | h3 { 26 | margin: 10px 0; 27 | } 28 | 29 | p { 30 | margin: 5px 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /vvmanager: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralfyang/vagrant_docker_cluster/f5c87fbe6491b24924a4dcecf842870e8fc174ad/vvmanager -------------------------------------------------------------------------------- /webconsole.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | EXECUTABLE_PATH="$(pwd)/vvmanager" 4 | PID_FILE="$(pwd)/vvmanager.pid" 5 | LOG_DIR="$(pwd)" 6 | LOG_FILE="$LOG_DIR/history.log" 7 | 8 | rotate_logs() { 9 | local max_files=4 10 | for ((i=max_files; i>0; i--)); do 11 | if [ -f "$LOG_FILE.$i" ]; then 12 | mv "$LOG_FILE.$i" "$LOG_FILE.$((i+1))" 13 | fi 14 | done 15 | if [ -f "$LOG_FILE" ]; then 16 | mv "$LOG_FILE" "$LOG_FILE.1" 17 | fi 18 | } 19 | 20 | case "$1" in 21 | start) 22 | if [ -f "$PID_FILE" ]; then 23 | echo "vvmanager is already running." 24 | exit 1 25 | fi 26 | rotate_logs 27 | nohup "$EXECUTABLE_PATH" run > "$LOG_FILE" 2>&1 & 28 | echo $! > "$PID_FILE" 29 | echo "vvmanager started." 30 | ;; 31 | stop) 32 | if [ ! -f "$PID_FILE" ]; then 33 | echo "vvmanager is not running." 34 | exit 1 35 | fi 36 | kill $(cat "$PID_FILE") 37 | rm "$PID_FILE" 38 | echo "vvmanager stopped." 39 | ;; 40 | restart) 41 | "$0" stop 42 | "$0" start 43 | ;; 44 | run) 45 | "$EXECUTABLE_PATH" run 46 | ;; 47 | *) 48 | echo "Usage: vvmanager {start|stop|restart|run}" 49 | exit 1 50 | ;; 51 | esac 52 | 53 | --------------------------------------------------------------------------------