forked from jan-leila/nix-config
		
	drafted out virt home assistant
This commit is contained in:
		
							parent
							
								
									ba5d5a1487
								
							
						
					
					
						commit
						77f1aa30b7
					
				
					 4 changed files with 270 additions and 75 deletions
				
			
		|  | @ -91,10 +91,10 @@ | ||||||
|         }; |         }; | ||||||
|       }; |       }; | ||||||
|     }; |     }; | ||||||
|     home-assistant = { |     # home-assistant = { | ||||||
|       enable = false; |     #   enable = false; | ||||||
|       subdomain = "home"; |     #   subdomain = "home"; | ||||||
|     }; |     # }; | ||||||
|     adguardhome = { |     adguardhome = { | ||||||
|       enable = false; |       enable = false; | ||||||
|     }; |     }; | ||||||
|  | @ -178,6 +178,12 @@ | ||||||
|       enable = true; |       enable = true; | ||||||
|       subdomain = "search"; |       subdomain = "search"; | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     virt-home-assistant = { | ||||||
|  |       enable = false; | ||||||
|  |       networkBridge = "bond0"; | ||||||
|  |       hostDevice = "0x10c4:0xea60"; | ||||||
|  |     }; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   # disable computer sleeping |   # disable computer sleeping | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ | ||||||
|     ./jellyfin.nix |     ./jellyfin.nix | ||||||
|     ./forgejo.nix |     ./forgejo.nix | ||||||
|     ./searx.nix |     ./searx.nix | ||||||
|     ./home-assistant.nix |     ./virt-home-assistant.nix | ||||||
|     ./adguardhome.nix |     ./adguardhome.nix | ||||||
|     ./immich.nix |     ./immich.nix | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| { | { | ||||||
|   lib, |   lib, | ||||||
|   config, |   config, | ||||||
|  |   inputs, | ||||||
|   ... |   ... | ||||||
| }: let | }: let | ||||||
|   configDir = "/var/lib/hass"; |   configDir = "/var/lib/hass"; | ||||||
|  | @ -16,81 +17,114 @@ in { | ||||||
| 
 | 
 | ||||||
|   config = lib.mkIf config.host.home-assistant.enable (lib.mkMerge [ |   config = lib.mkIf config.host.home-assistant.enable (lib.mkMerge [ | ||||||
|     { |     { | ||||||
|       systemd.tmpfiles.rules = [ |       virtualisation.libvirt = { | ||||||
|         "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" |         swtpm.enable = true; | ||||||
|  |         connections."qemu:///session" = { | ||||||
|  |           networks = [ | ||||||
|  |             { | ||||||
|  |               definition = inputs.nix-virt.lib.network.writeXML (inputs.nix-virt.lib.network.templates.bridge | ||||||
|  |                 { | ||||||
|  |                   uuid = "d57e37e2-311f-4e5c-a484-97c2210c2770"; | ||||||
|  |                   subnet_byte = 71; | ||||||
|  |                 }); | ||||||
|  |               active = true; | ||||||
|  |             } | ||||||
|           ]; |           ]; | ||||||
|       services.home-assistant = { |           domains = [ | ||||||
|         enable = true; |             { | ||||||
|         configDir = configDir; |               definition = inputs.nix-virt.lib.domain.writeXML (inputs.nix-virt.lib.domain.templates.linux | ||||||
|         extraComponents = [ |                 { | ||||||
|           "met" |                   name = "Home Assistant"; | ||||||
|           "radio_browser" |                   uuid = "c5cc0efc-6101-4c1d-be31-acbba203ccde"; | ||||||
|           "isal" |                   memory = { | ||||||
|           "zha" |                     count = 4; | ||||||
|           "jellyfin" |                     unit = "GiB"; | ||||||
|           "webostv" |  | ||||||
|           "tailscale" |  | ||||||
|           "syncthing" |  | ||||||
|           "sonos" |  | ||||||
|           "analytics_insights" |  | ||||||
|           "unifi" |  | ||||||
|           "openweathermap" |  | ||||||
|         ]; |  | ||||||
|         config = { |  | ||||||
|           http = { |  | ||||||
|             server_port = 8082; |  | ||||||
|             use_x_forwarded_for = true; |  | ||||||
|             trusted_proxies = ["127.0.0.1" "::1"]; |  | ||||||
|             ip_ban_enabled = true; |  | ||||||
|             login_attempts_threshold = 10; |  | ||||||
|                   }; |                   }; | ||||||
|           # recorder.db_url = "postgresql://@/${db_user}"; |                   # storage_vol = { | ||||||
|           "automation manual" = []; |                   #   pool = "MyPool"; | ||||||
|           "automation ui" = "!include automations.yaml"; |                   #   volume = "Penguin.qcow2"; | ||||||
|         }; |                   # }; | ||||||
|         extraPackages = python3Packages: |                 }); | ||||||
|           with python3Packages; [ |             } | ||||||
|             hassil |  | ||||||
|             numpy |  | ||||||
|             gtts |  | ||||||
|           ]; |           ]; | ||||||
|         }; |         }; | ||||||
|       host = { |  | ||||||
|         reverse_proxy.subdomains.${config.host.home-assistant.subdomain} = { |  | ||||||
|           target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; |  | ||||||
| 
 |  | ||||||
|           websockets.enable = true; |  | ||||||
|           forwardHeaders.enable = true; |  | ||||||
| 
 |  | ||||||
|           extraConfig = '' |  | ||||||
|             add_header Upgrade $http_upgrade; |  | ||||||
|             add_header Connection \"upgrade\"; |  | ||||||
| 
 |  | ||||||
|             proxy_buffering off; |  | ||||||
| 
 |  | ||||||
|             proxy_read_timeout 90; |  | ||||||
|           ''; |  | ||||||
|         }; |  | ||||||
|       }; |       }; | ||||||
|  | 
 | ||||||
|  |       # systemd.tmpfiles.rules = [ | ||||||
|  |       #   "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" | ||||||
|  |       # ]; | ||||||
|  |       # services.home-assistant = { | ||||||
|  |       #   enable = true; | ||||||
|  |       #   configDir = configDir; | ||||||
|  |       #   extraComponents = [ | ||||||
|  |       #     "met" | ||||||
|  |       #     "radio_browser" | ||||||
|  |       #     "isal" | ||||||
|  |       #     "zha" | ||||||
|  |       #     "jellyfin" | ||||||
|  |       #     "webostv" | ||||||
|  |       #     "tailscale" | ||||||
|  |       #     "syncthing" | ||||||
|  |       #     "sonos" | ||||||
|  |       #     "analytics_insights" | ||||||
|  |       #     "unifi" | ||||||
|  |       #     "openweathermap" | ||||||
|  |       #   ]; | ||||||
|  |       #   config = { | ||||||
|  |       #     http = { | ||||||
|  |       #       server_port = 8082; | ||||||
|  |       #       use_x_forwarded_for = true; | ||||||
|  |       #       trusted_proxies = ["127.0.0.1" "::1"]; | ||||||
|  |       #       ip_ban_enabled = true; | ||||||
|  |       #       login_attempts_threshold = 10; | ||||||
|  |       #     }; | ||||||
|  |       #     # recorder.db_url = "postgresql://@/${db_user}"; | ||||||
|  |       #     "automation manual" = []; | ||||||
|  |       #     "automation ui" = "!include automations.yaml"; | ||||||
|  |       #   }; | ||||||
|  |       #   extraPackages = python3Packages: | ||||||
|  |       #     with python3Packages; [ | ||||||
|  |       #       hassil | ||||||
|  |       #       numpy | ||||||
|  |       #       gtts | ||||||
|  |       #     ]; | ||||||
|  |       # }; | ||||||
|  |       # host = { | ||||||
|  |       #   reverse_proxy.subdomains.${config.host.home-assistant.subdomain} = { | ||||||
|  |       #     target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; | ||||||
|  | 
 | ||||||
|  |       #     websockets.enable = true; | ||||||
|  |       #     forwardHeaders.enable = true; | ||||||
|  | 
 | ||||||
|  |       #     extraConfig = '' | ||||||
|  |       #       add_header Upgrade $http_upgrade; | ||||||
|  |       #       add_header Connection \"upgrade\"; | ||||||
|  | 
 | ||||||
|  |       #       proxy_buffering off; | ||||||
|  | 
 | ||||||
|  |       #       proxy_read_timeout 90; | ||||||
|  |       #     ''; | ||||||
|  |       #   }; | ||||||
|  |       # }; | ||||||
|     } |     } | ||||||
|     (lib.mkIf config.host.impermanence.enable { |     (lib.mkIf config.host.impermanence.enable { | ||||||
|       assertions = [ |       # assertions = [ | ||||||
|         { |       #   { | ||||||
|           assertion = config.services.home-assistant.configDir == configDir; |       #     assertion = config.services.home-assistant.configDir == configDir; | ||||||
|           message = "home assistant config directory does not match persistence"; |       #     message = "home assistant config directory does not match persistence"; | ||||||
|         } |       #   } | ||||||
|       ]; |       # ]; | ||||||
|       environment.persistence."/persist/system/root" = { |       # environment.persistence."/persist/system/root" = { | ||||||
|         enable = true; |       #   enable = true; | ||||||
|         hideMounts = true; |       #   hideMounts = true; | ||||||
|         directories = [ |       #   directories = [ | ||||||
|           { |       #     { | ||||||
|             directory = configDir; |       #       directory = configDir; | ||||||
|             user = "hass"; |       #       user = "hass"; | ||||||
|             group = "hass"; |       #       group = "hass"; | ||||||
|           } |       #     } | ||||||
|         ]; |       #   ]; | ||||||
|       }; |       # }; | ||||||
|     }) |     }) | ||||||
|   ]); |   ]); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										155
									
								
								modules/nixos-modules/server/virt-home-assistant.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								modules/nixos-modules/server/virt-home-assistant.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | ||||||
|  | { | ||||||
|  |   config, | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services.virt-home-assistant = { | ||||||
|  |     enable = lib.mkEnableOption "Wether to enable home assistant virtual machine"; | ||||||
|  |     networkBridge = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "what network bridge should we attach to the image"; | ||||||
|  |     }; | ||||||
|  |     hostDevice = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "what host devices should be attached to the image"; | ||||||
|  |     }; | ||||||
|  |     initialVersion = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "what home assistant image version should we pull for initial instal"; | ||||||
|  |       default = "15.0"; | ||||||
|  |     }; | ||||||
|  |     imageName = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "where should the image be installed to"; | ||||||
|  |       default = "home-assistant.qcow2"; | ||||||
|  |     }; | ||||||
|  |     installLocation = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "where should the image be installed to"; | ||||||
|  |       default = "/etc/hass"; | ||||||
|  |     }; | ||||||
|  |     virtualMachineName = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "what name should we give the virtual machine"; | ||||||
|  |       default = "home-assistant"; | ||||||
|  |     }; | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "subdomain of base domain that home-assistant will be hosted at"; | ||||||
|  |       default = "home-assistant"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  |   config = lib.mkIf config.services.virt-home-assistant.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       # environment.systemPackages = with pkgs; [ | ||||||
|  |       #   virt-manager | ||||||
|  |       # ]; | ||||||
|  | 
 | ||||||
|  |       # TODO: move this to external module and just have an assertion here that its enabled | ||||||
|  |       # enable virtualization on the system | ||||||
|  |       virtualisation = { | ||||||
|  |         libvirtd = { | ||||||
|  |           enable = true; | ||||||
|  |           qemu.ovmf.enable = true; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       # TODO: deactivation script? | ||||||
|  |       # create service to install and start the container | ||||||
|  |       systemd.services.virt-install-home-assistant = let | ||||||
|  |         # TODO: all of these need to be escaped to be used in commands reliably | ||||||
|  |         bridgedNetwork = config.services.virt-home-assistant.networkBridge; | ||||||
|  |         hostDevice = config.services.virt-home-assistant.hostDevice; | ||||||
|  |         virtualMachineName = config.services.virt-home-assistant.virtualMachineName; | ||||||
|  |         imageName = config.services.virt-home-assistant.imageName; | ||||||
|  |         installLocation = config.services.virt-home-assistant.installLocation; | ||||||
|  |         installImage = "${installLocation}/${imageName}"; | ||||||
|  |         initialVersion = config.services.virt-home-assistant.initialVersion; | ||||||
|  | 
 | ||||||
|  |         home-assistant-qcow2 = pkgs.fetchurl { | ||||||
|  |           name = "home-assistant.qcow2"; | ||||||
|  |           url = "https://github.com/home-assistant/operating-system/releases/download/${initialVersion}/haos_ova-${initialVersion}.qcow2.xz"; | ||||||
|  |           hash = "sha256-V1BEjvvLNbMMKJVyMCmipjQ/3owoJteeVxoF9LDHo1U="; | ||||||
|  |           postFetch = '' | ||||||
|  |             cp $out src.xz | ||||||
|  |             rm -r $out | ||||||
|  |             ${pkgs.xz}/bin/unxz src.xz --stdout > $out/${imageName} | ||||||
|  |           ''; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         # Write a script to install the Home Assistant OS qcow2 image | ||||||
|  |         virtInstallScript = pkgs.writeShellScriptBin "virt-install-hass" '' | ||||||
|  |           # Copy the initial image out of the package store to the install location if we don't have one yet | ||||||
|  |           if [ ! -f ${installImage} ]; then | ||||||
|  |             cp ${home-assistant-qcow2} ${installLocation} | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |           # Check if VM already exists, and other pre-conditions | ||||||
|  |           if ! ${pkgs.libvirt}/bin/virsh list --all | grep -q ${virtualMachineName}; then | ||||||
|  |             ${pkgs.virt-manager}/bin/virt-install --name ${virtualMachineName} \ | ||||||
|  |               --description "Home Assistant OS" \ | ||||||
|  |               --os-variant=generic \ | ||||||
|  |               --boot uefi \ | ||||||
|  |               --ram=2048 \ | ||||||
|  |               --vcpus=2 \ | ||||||
|  |               --import \ | ||||||
|  |               --disk ${installImage},bus=sata \ | ||||||
|  |               --network bridge=${bridgedNetwork} \ | ||||||
|  |               --host-device ${hostDevice} \ | ||||||
|  |               --graphics none | ||||||
|  |             ${pkgs.libvirt}/bin/virsh autostart ${virtualMachineName} | ||||||
|  |           fi | ||||||
|  |         ''; | ||||||
|  |       in { | ||||||
|  |         description = "Install and start Home Assistant"; | ||||||
|  |         wantedBy = ["multi-user.target"]; | ||||||
|  |         after = ["local-fs.target"]; | ||||||
|  |         requires = ["libvirtd.service"]; | ||||||
|  |         serviceConfig.Type = "oneshot"; | ||||||
|  |         serviceConfig = { | ||||||
|  |           ExecStart = "${virtInstallScript}/bin/virt-install-hass"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       # TODO: figure out what we need to proxy to the virtual image | ||||||
|  |       # host = { | ||||||
|  |       #   reverse_proxy.subdomains.${config.services.virt-home-assistant.subdomain} = { | ||||||
|  |       #     target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; | ||||||
|  | 
 | ||||||
|  |       #     websockets.enable = true; | ||||||
|  |       #     forwardHeaders.enable = true; | ||||||
|  | 
 | ||||||
|  |       #     extraConfig = '' | ||||||
|  |       #       add_header Upgrade $http_upgrade; | ||||||
|  |       #       add_header Connection \"upgrade\"; | ||||||
|  | 
 | ||||||
|  |       #       proxy_buffering off; | ||||||
|  | 
 | ||||||
|  |       #       proxy_read_timeout 90; | ||||||
|  |       #     ''; | ||||||
|  |       #   }; | ||||||
|  |       # }; | ||||||
|  |     } | ||||||
|  |     (lib.mkIf config.services.fail2ban.enable { | ||||||
|  |       # TODO: figure out how to write a config for this, prob based on nginx proxy logs? | ||||||
|  |     }) | ||||||
|  |     (lib.mkIf config.host.impermanence.enable { | ||||||
|  |       # assertions = [ | ||||||
|  |       #   { | ||||||
|  |       #     assertion = config.services.virt-home-assistant.installLocation == configDir; | ||||||
|  |       #     message = "home assistant install location does not match persistence"; | ||||||
|  |       #   } | ||||||
|  |       # ]; | ||||||
|  |       environment.persistence."/persist/system/root" = { | ||||||
|  |         enable = true; | ||||||
|  |         hideMounts = true; | ||||||
|  |         directories = [ | ||||||
|  |           { | ||||||
|  |             directory = config.services.virt-home-assistant.installLocation; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       }; | ||||||
|  |     }) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue