#!/bin/bash new_instance() { #reset detection info UDEV='' TEMPUSB='' USB='' #It is possible to not create an instance after preparing,so check if this is the first if [ -f /etc/octodocker_instances ]; then firstrun=false else firstrun=true fi #We can also pass this directly, from prepare.sh firstrun=$1 TEMPLATE='' get_settings if [ $SUDO_USER ]; then user=$SUDO_USER; fi SCRIPTDIR=$(dirname $(readlink -f $0)) while true; do echo "${green}Enter the name for new printer/instance (no spaces):${white}" read INSTANCE if [ -z "$INSTANCE" ]; then echo "Please provide an instance name" continue fi if ! has-space "$INSTANCE"; then break else echo "Instance names must not have spaces" fi done if [ "$firstrun" != "true" ]; then if [ -d "/opt/octoprint/$INSTANCE" ]; then echo "Already have an entry for $INSTANCE. Exiting." main_menu fi #Choose if should use an instance as template here echo echo echo echo "Using a template instance allows you to copy config settings" echo "and gcode files from one instance to your new instance." if prompt_confirm "Use an existing instance as a template?"; then PS3="${cyan}Select template instance: ${white}" get_instances true select opt in "${INSTANCE_ARR[@]}" do if [ "$opt" == Quit ]; then main_menu fi TEMPLATE=$opt echo "Using $opt as template." break done PS3="${cyan}Select what components of the template to copy: ${white}" options=("Config Only" "Config and Gcode") select opt in "${options[@]}" do case $opt in "Config Only") COPY=1 break ;; "Config and Gcode") COPY=2 break ;;*) echo "invalid option $REPLY";; esac done else TEMPLATE='' fi fi if prompt_confirm "Ready to begin instance creation?"; then PORT=5000 PORTS_INUSE=$(join_by , $(cat /etc/octodocker_instances 2>/dev/null | sed -n -e 's/^.*\(port:\)\(.*\) udev:.*/\2/p')) until [[ "${PORTS_INUSE}" != *"${PORT}"* ]]; do ((PORT++)); done echo Selected port is: $PORT OCTOCONFIG="/opt/octoprint" echo "Your new OctoPrint instance will be installed at ${cyan}/opt/octoprint/$INSTANCE${white}" echo echo else if [ "$firstrun" == "true" ]; then echo "${red}You will need to restart your installation.${white}" echo "${red}Answer Y and re-run octodocker_deploy${white}" remove_everything exit else main_menu fi fi if [ -n "$TEMPLATE" ]; then BFOLD="/opt/octoprint/$INSTANCE$TEMPLATE" #check to make sure first run is complete if grep -q 'firstRun: true' $BFOLD/config.yaml; then echo "Template profile and admin user will have to be setup." main_menu fi fi echo "Printer auto-detection must be completed before an instance can be created." if prompt_confirm "Begin printer auto-detection for udev entry?"; then detect_printer else if [ "$firstrun" == "true" ]; then echo "${magenta}First instance setup in progress, continuing${white}" else echo "${magenta}Instance has not been created. Restart and do detection when you are ready.${white}" main_menu fi fi #Detection phase printer_udev false #USB cameras if [ "$firstrun" != "true" ]; then if prompt_confirm "Would you like to auto detect an associated USB camera?"; then add_camera fi fi if prompt_confirm "Ready to write all changes. Do you want to proceed?"; then mkdir $OCTOCONFIG/$INSTANCE cat $SCRIPTDIR/docker-compose.yml | sed -e "s/NEWINSTANCE/$INSTANCE/" -e "s/CAMPORT/$CAMPORT/" -e "s/NEWPORT/$PORT/" > $OCTOCONFIG/$INSTANCE/docker-compose.yml #write phase if [ -n "$UDEV" ] || [ -n "$USB" ]; then printer_udev true fi #Append instance name to list for removal tool if [ -z "$UDEV" ] && [ -z "$USB" ]; then echo "instance:$INSTANCE port:$PORT udev:false" >> /etc/octodocker_instances else echo "instance:$INSTANCE port:$PORT udev:true" >> /etc/octodocker_instances fi if [ -n "$TEMPLATE" ]; then echo "${magenta}Copying template files....${white}" if [ $COPY -eq 1 ]; then rsync -r \ --exclude 'timelapse' \ --exclude 'uploads' \ --exclude 'logs' \ $BFOLD/* $OCTOCONFIG/$INSTANCE/octoprint/ fi if [ $COPY -eq 2 ]; then rsync -r \ --exclude 'timelapse' \ --exclude 'logs' \ $BFOLD/* $OCTOCONFIG/$INSTANCE/octoprint/ fi fi #build docker docker compose -f $OCTOCONFIG/$INSTANCE/docker-compose.yml up -d #uniquify instances echo 'Uniquifying instance...' BASE=$OCTOCONFIG/$INSTANCE docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set appearance.name $INSTANCE docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set server.commands.serverRestartCommand "sudo systemctl restart $INSTANCE" docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set server.commands.systemRestartCommand "sudo reboot" docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set plugins.discovery.upnpUuid $(uuidgen) docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set plugins.errortracking.unique_id $(uuidgen) docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set plugins.tracking.unique_id $(uuidgen) docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set serial.port /dev/octo_$INSTANCE #clear additional ports docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config remove serial.additionalPorts docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config append_value serial.additionalPorts "/dev/octo_$INSTANCE" docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set feature.modelSizeDetection false --bool docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set webcam.ffmpeg /usr/bin/ffmpeg if [ "$HAPROXY" == true ]; then HAversion=$(haproxy -v | sed -n 's/^.*version \([0-9]\).*/\1/p') SEDREPLACE="#$INSTANCE start\n\ acl is_$INSTANCE url_beg /$INSTANCE\n\ http-request redirect scheme http drop-query append-slash if is_$INSTANCE ! { path_beg /$INSTANCE/ }\n\ use_backend $INSTANCE if { path_beg /$INSTANCE/ }\n\ #$INSTANCE stop" sed -i "/option forwardfor except 127.0.0.1/a $SEDREPLACE" /etc/haproxy/haproxy.cfg echo "#$INSTANCE start" >> /etc/haproxy/haproxy.cfg echo "backend $INSTANCE" >> /etc/haproxy/haproxy.cfg if [ $HAversion -gt 1 ]; then echo " http-request replace-path /$INSTANCE/(.*) /\1" >> /etc/haproxy/haproxy.cfg echo " acl needs_scheme req.hdr_cnt(X-Scheme) eq 0" >> /etc/haproxy/haproxy.cfg echo " http-request add-header X-Scheme https if needs_scheme { ssl_fc }" >> /etc/haproxy/haproxy.cfg echo " http-request add-header X-Scheme http if needs_scheme !{ ssl_fc }" >> /etc/haproxy/haproxy.cfg echo " http-request add-header X-Script-Name /$INSTANCE" >> /etc/haproxy/haproxy.cfg echo " server octoprint1 127.0.0.1:$PORT" >> /etc/haproxy/haproxy.cfg echo " option forwardfor" >> /etc/haproxy/haproxy.cfg else echo " reqrep ^([^\ :]*)\ /$INSTANCE/(.*) \1\ /\2" >> /etc/haproxy/haproxy.cfg echo " server octoprint1 127.0.0.1:$PORT" >> /etc/haproxy/haproxy.cfg echo " option forwardfor" >> /etc/haproxy/haproxy.cfg echo " acl needs_scheme req.hdr_cnt(X-Scheme) eq 0" >> /etc/haproxy/haproxy.cfg echo " reqadd X-Scheme:\ https if needs_scheme { ssl_fc }" >> /etc/haproxy/haproxy.cfg echo " reqadd X-Scheme:\ http if needs_scheme !{ ssl_fc }" >> /etc/haproxy/haproxy.cfg echo " reqadd X-Script-Name:\ /$INSTANCE" >> /etc/haproxy/haproxy.cfg fi echo "#$INSTANCE stop" >> /etc/haproxy/haproxy.cfg #restart haproxy sudo systemctl restart haproxy.service fi if [[ -n $CAM || -n $USBCAM ]]; then write_camera fi #Reset udev udevadm control --reload-rules udevadm trigger # systemctl daemon-reload sleep 1 #restart docker docker restart $INSTANCE systemctl enable $INSTANCE.service if [[ -n $CAM || -n $USBCAM || -n $BYIDCAM ]]; then systemctl start cam_$INSTANCE.service systemctl enable cam_$INSTANCE.service fi else main_menu fi if [ "$firstrun" == "true" ]; then firstrun_install else main_menu fi } detect_printer() { echo echo dmesg -C echo "Plug your printer in via USB now (detection time-out in 1 min)" counter=0 while [[ -z "$UDEV" ]] && [[ $counter -lt 60 ]]; do TEMPUSB=$(dmesg | sed -n -e 's/^.*\(cdc_acm\|ftdi_sio\|ch341\|cp210x\|ch34x\) \([0-9].*[0-9]\): \(tty.*\|FTD.*\|ch341-uart.*\|cp210x\|ch34x\).*/\2/p') UDEV=$(dmesg | sed -n -e 's/^.*SerialNumber: //p') counter=$(( $counter + 1 )) if [[ -n "$TEMPUSB" ]] && [[ -z "$UDEV" ]]; then break fi sleep 1 done dmesg -C } printer_udev() { write=$1 if [ "$write" == true ]; then #Printer udev identifier technique - either Serial number or USB port #Serial Number if [ -n "$UDEV" ]; then echo SUBSYSTEM==\"tty\", ATTRS{serial}==\"$UDEV\", SYMLINK+=\"octo_$INSTANCE\" >> /etc/udev/rules.d/99-octoprint.rules fi #USB port if [ -n "$USB" ]; then echo KERNELS==\"$USB\",SUBSYSTEM==\"tty\",SYMLINK+=\"octo_$INSTANCE\" >> /etc/udev/rules.d/99-octoprint.rules fi else #No serial number if [ -z "$UDEV" ] && [ -n "$TEMPUSB" ]; then echo "Printer Serial Number not detected." echo "The physical USB port will be used." echo "USB hubs and printers detected this way must stay plugged into the same USB positions on your machine." echo USB=$TEMPUSB echo "Your printer will be setup at the following usb address: ${cyan}$USB${white}" echo else echo -e "Serial number detected as: ${cyan}$UDEV${white}" check_sn "$UDEV" echo fi #Failed state. Nothing detected if [ -z "$UDEV" ] && [ -z "$TEMPUSB" ]; then if [ "$firstrun" == "false" ]; then echo echo "${red}No printer was detected during the detection period.${white}" echo "Check your USB cable (power only?) and try again." echo echo main_menu else echo "You can add a udev rule later from the Utilities menu." fi fi fi } remove_instance() { opt=$1 #stop and remove docker if [ "$(docker ps -a | grep $opt)" ]; then docker stop $opt docker rm $opt fi #Get all cameras associated with this instance. #Is this right? get_cameras for camera in "${CAMERA_ARR[@]}"; do remove_camera $camera done #remove udev entry sed -i "/$opt/d" /etc/udev/rules.d/99-octoprint.rules #remove files rm -rf /opt/octoprint/s$opt #remove from octoprint_instances sed -i "/$opt/d" /etc/octodocker_instances #remove haproxy entry if [ "$HAPROXY" == true ]; then sed -i "/use_backend $opt/d" /etc/haproxy/haproxy.cfg sed -i "/#$opt start/,/#$opt stop/d" /etc/haproxy/haproxy.cfg systemctl restart haproxy.service fi }