mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-31 16:11:03 +01:00 
			
		
		
		
	Merge master
This commit is contained in:
		
						commit
						e631c6f7e0
					
				
							
								
								
									
										17
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -22,30 +22,21 @@ jobs: | |||||||
|         uses: tj-actions/changed-files@v14.1 |         uses: tj-actions/changed-files@v14.1 | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|  |             *.nix | ||||||
|             go.* |             go.* | ||||||
|             **/*.go |             **/*.go | ||||||
|             integration_test/ |             integration_test/ | ||||||
|             config-example.yaml |             config-example.yaml | ||||||
| 
 | 
 | ||||||
|       - name: Setup Go |       - uses: cachix/install-nix-action@v16 | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         uses: actions/setup-go@v2 |  | ||||||
|         with: |  | ||||||
|           go-version: "1.18.0" |  | ||||||
| 
 |  | ||||||
|       - name: Install dependencies |  | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |  | ||||||
|         run: | |  | ||||||
|           go version |  | ||||||
|           sudo apt update |  | ||||||
|           sudo apt install -y make |  | ||||||
| 
 | 
 | ||||||
|       - name: Run build |       - name: Run build | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         run: make build |         run: nix build | ||||||
| 
 | 
 | ||||||
|       - uses: actions/upload-artifact@v2 |       - uses: actions/upload-artifact@v2 | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         with: |         with: | ||||||
|           name: headscale-linux |           name: headscale-linux | ||||||
|           path: headscale |           path: result/bin/headscale | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							| @ -16,6 +16,7 @@ jobs: | |||||||
|         uses: tj-actions/changed-files@v14.1 |         uses: tj-actions/changed-files@v14.1 | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|  |             *.nix | ||||||
|             go.* |             go.* | ||||||
|             **/*.go |             **/*.go | ||||||
|             integration_test/ |             integration_test/ | ||||||
| @ -25,7 +26,7 @@ jobs: | |||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         uses: golangci/golangci-lint-action@v2 |         uses: golangci/golangci-lint-action@v2 | ||||||
|         with: |         with: | ||||||
|           version: latest |           version: v1.46.1 | ||||||
| 
 | 
 | ||||||
|           # Only block PRs on new problems. |           # Only block PRs on new problems. | ||||||
|           # If this is not enabled, we will end up having PRs |           # If this is not enabled, we will end up having PRs | ||||||
| @ -45,6 +46,7 @@ jobs: | |||||||
|         uses: tj-actions/changed-files@v14.1 |         uses: tj-actions/changed-files@v14.1 | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|  |             *.nix | ||||||
|             **/*.md |             **/*.md | ||||||
|             **/*.yml |             **/*.yml | ||||||
|             **/*.yaml |             **/*.yaml | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								.github/workflows/test-integration.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/test-integration.yml
									
									
									
									
										vendored
									
									
								
							| @ -16,17 +16,15 @@ jobs: | |||||||
|         uses: tj-actions/changed-files@v14.1 |         uses: tj-actions/changed-files@v14.1 | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|  |             *.nix | ||||||
|             go.* |             go.* | ||||||
|             **/*.go |             **/*.go | ||||||
|             integration_test/ |             integration_test/ | ||||||
|             config-example.yaml |             config-example.yaml | ||||||
| 
 | 
 | ||||||
|       - name: Setup Go |       - uses: cachix/install-nix-action@v16 | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         uses: actions/setup-go@v2 |  | ||||||
|         with: |  | ||||||
|           go-version: "1.18.0" |  | ||||||
| 
 | 
 | ||||||
|       - name: Run Integration tests |       - name: Run Integration tests | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         run: make test_integration |         run: nix develop --command -- make test_integration | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							| @ -16,28 +16,15 @@ jobs: | |||||||
|         uses: tj-actions/changed-files@v14.1 |         uses: tj-actions/changed-files@v14.1 | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|  |             *.nix | ||||||
|             go.* |             go.* | ||||||
|             **/*.go |             **/*.go | ||||||
|             integration_test/ |             integration_test/ | ||||||
|             config-example.yaml |             config-example.yaml | ||||||
| 
 | 
 | ||||||
|       - name: Setup Go |       - uses: cachix/install-nix-action@v16 | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         uses: actions/setup-go@v2 |  | ||||||
|         with: |  | ||||||
|           go-version: "1.18.0" |  | ||||||
| 
 |  | ||||||
|       - name: Install dependencies |  | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |  | ||||||
|         run: | |  | ||||||
|           go version |  | ||||||
|           sudo apt update |  | ||||||
|           sudo apt install -y make |  | ||||||
| 
 | 
 | ||||||
|       - name: Run tests |       - name: Run tests | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |         if: steps.changed-files.outputs.any_changed == 'true' | ||||||
|         run: make test |         run: nix develop --check | ||||||
| 
 |  | ||||||
|       - name: Run build |  | ||||||
|         if: steps.changed-files.outputs.any_changed == 'true' |  | ||||||
|         run: make |  | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -28,6 +28,6 @@ derp.yaml | |||||||
| 
 | 
 | ||||||
| test_output/  | test_output/  | ||||||
| 
 | 
 | ||||||
| # Nix and direnv | # Nix build output | ||||||
| .direnv/ |  | ||||||
| result | result | ||||||
|  | .direnv/ | ||||||
|  | |||||||
| @ -24,6 +24,8 @@ linters: | |||||||
|     - tagliatelle |     - tagliatelle | ||||||
|     - godox |     - godox | ||||||
|     - ireturn |     - ireturn | ||||||
|  |     - execinquery | ||||||
|  |     - exhaustruct | ||||||
| 
 | 
 | ||||||
|     # We should strive to enable these: |     # We should strive to enable these: | ||||||
|     - wrapcheck |     - wrapcheck | ||||||
|  | |||||||
| @ -7,6 +7,12 @@ | |||||||
| - Headscale fails to serve if the ACL policy file cannot be parsed [#537](https://github.com/juanfont/headscale/pull/537) | - Headscale fails to serve if the ACL policy file cannot be parsed [#537](https://github.com/juanfont/headscale/pull/537) | ||||||
| - Fix labels cardinality error when registering unknown pre-auth key [#519](https://github.com/juanfont/headscale/pull/519) | - Fix labels cardinality error when registering unknown pre-auth key [#519](https://github.com/juanfont/headscale/pull/519) | ||||||
| - Fix send on closed channel crash in polling [#542](https://github.com/juanfont/headscale/pull/542) | - Fix send on closed channel crash in polling [#542](https://github.com/juanfont/headscale/pull/542) | ||||||
|  | - Fixed spurious calls to setLastStateChangeToNow from ephemeral nodes [#566](https://github.com/juanfont/headscale/pull/566) | ||||||
|  | - Add command for moving nodes between namespaces [#362](https://github.com/juanfont/headscale/issues/362) | ||||||
|  | - Added more configuration parameters for OpenID Connect (scopes, free-form paramters, domain and user allowlist) | ||||||
|  | - Add command to set tags on a node [#525](https://github.com/juanfont/headscale/issues/525) | ||||||
|  | - Add command to view tags of nodes [#356](https://github.com/juanfont/headscale/issues/356) | ||||||
|  | - Add --all (-a) flag to enable routes command [#360](https://github.com/juanfont/headscale/issues/360) | ||||||
| 
 | 
 | ||||||
| ## 0.15.0 (2022-03-20) | ## 0.15.0 (2022-03-20) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										58
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								README.md
									
									
									
									
									
								
							| @ -91,6 +91,10 @@ Please have a look at the documentation under [`docs/`](docs/). | |||||||
| To contribute to headscale you would need the lastest version of [Go](https://golang.org) | To contribute to headscale you would need the lastest version of [Go](https://golang.org) | ||||||
| and [Buf](https://buf.build)(Protobuf generator). | and [Buf](https://buf.build)(Protobuf generator). | ||||||
| 
 | 
 | ||||||
|  | We recommend using [Nix](https://nixos.org/) to setup a development environment. This can | ||||||
|  | be done with `nix develop`, which will install the tools and give you a shell. | ||||||
|  | This guarantees that you will have the same dev env as `headscale` maintainers. | ||||||
|  | 
 | ||||||
| PRs and suggestions are welcome. | PRs and suggestions are welcome. | ||||||
| 
 | 
 | ||||||
| ### Code style | ### Code style | ||||||
| @ -115,10 +119,12 @@ Check out the `.golangci.yaml` and `Makefile` to see the specific configuration. | |||||||
| 
 | 
 | ||||||
| - Go | - Go | ||||||
| - Buf | - Buf | ||||||
| - Protobuf tools: | - Protobuf tools | ||||||
|  | 
 | ||||||
|  | Install and activate: | ||||||
| 
 | 
 | ||||||
| ```shell | ```shell | ||||||
| make install-protobuf-plugins | nix develop | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### Testing and building | ### Testing and building | ||||||
| @ -140,6 +146,12 @@ make test | |||||||
| 
 | 
 | ||||||
| To build the program: | To build the program: | ||||||
| 
 | 
 | ||||||
|  | ```shell | ||||||
|  | nix build | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | or | ||||||
|  | 
 | ||||||
| ```shell | ```shell | ||||||
| make build | make build | ||||||
| ``` | ``` | ||||||
| @ -264,6 +276,13 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Hoàng Đức Hiếu</b></sub> |             <sub style="font-size:14px"><b>Hoàng Đức Hiếu</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|  |         <a href=https://github.com/deonthomasgy> | ||||||
|  |             <img src=https://avatars.githubusercontent.com/u/150036?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Deon Thomas/> | ||||||
|  |             <br /> | ||||||
|  |             <sub style="font-size:14px"><b>Deon Thomas</b></sub> | ||||||
|  |         </a> | ||||||
|  |     </td> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/mevansam> |         <a href=https://github.com/mevansam> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/403630?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Mevan Samaratunga/> |             <img src=https://avatars.githubusercontent.com/u/403630?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Mevan Samaratunga/> | ||||||
| @ -271,6 +290,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Mevan Samaratunga</b></sub> |             <sub style="font-size:14px"><b>Mevan Samaratunga</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/dragetd> |         <a href=https://github.com/dragetd> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/3639577?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Michael G./> |             <img src=https://avatars.githubusercontent.com/u/3639577?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Michael G./> | ||||||
| @ -278,8 +299,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Michael G.</b></sub> |             <sub style="font-size:14px"><b>Michael G.</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/ptman> |         <a href=https://github.com/ptman> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/24669?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Paul Tötterman/> |             <img src=https://avatars.githubusercontent.com/u/24669?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Paul Tötterman/> | ||||||
| @ -315,6 +334,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Stefan Majer</b></sub> |             <sub style="font-size:14px"><b>Stefan Majer</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/lachy2849> |         <a href=https://github.com/lachy2849> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/98844035?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=lachy2849/> |             <img src=https://avatars.githubusercontent.com/u/98844035?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=lachy2849/> | ||||||
| @ -322,8 +343,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b>lachy2849</b></sub> |             <sub style="font-size:14px"><b>lachy2849</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/t56k> |         <a href=https://github.com/t56k> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/12165422?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=thomas/> |             <img src=https://avatars.githubusercontent.com/u/12165422?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=thomas/> | ||||||
| @ -338,6 +357,13 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Abraham Ingersoll</b></sub> |             <sub style="font-size:14px"><b>Abraham Ingersoll</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|  |         <a href=https://github.com/apognu> | ||||||
|  |             <img src=https://avatars.githubusercontent.com/u/3017182?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Antoine POPINEAU/> | ||||||
|  |             <br /> | ||||||
|  |             <sub style="font-size:14px"><b>Antoine POPINEAU</b></sub> | ||||||
|  |         </a> | ||||||
|  |     </td> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/aofei> |         <a href=https://github.com/aofei> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/5037285?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Aofei Sheng/> |             <img src=https://avatars.githubusercontent.com/u/5037285?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Aofei Sheng/> | ||||||
| @ -352,6 +378,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Arthur Woimbée</b></sub> |             <sub style="font-size:14px"><b>Arthur Woimbée</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/stensonb> |         <a href=https://github.com/stensonb> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/933389?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Bryan Stenson/> |             <img src=https://avatars.githubusercontent.com/u/933389?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Bryan Stenson/> | ||||||
| @ -366,8 +394,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b> Carson Yang</b></sub> |             <sub style="font-size:14px"><b> Carson Yang</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/fkr> |         <a href=https://github.com/fkr> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/51063?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Felix Kronlage-Dammers/> |             <img src=https://avatars.githubusercontent.com/u/51063?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Felix Kronlage-Dammers/> | ||||||
| @ -396,6 +422,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Jamie Greeff</b></sub> |             <sub style="font-size:14px"><b>Jamie Greeff</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/jimt> |         <a href=https://github.com/jimt> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/180326?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jim Tittsler/> |             <img src=https://avatars.githubusercontent.com/u/180326?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jim Tittsler/> | ||||||
| @ -410,8 +438,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Pierre Carru</b></sub> |             <sub style="font-size:14px"><b>Pierre Carru</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/rcursaru> |         <a href=https://github.com/rcursaru> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/16259641?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=rcursaru/> |             <img src=https://avatars.githubusercontent.com/u/16259641?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=rcursaru/> | ||||||
| @ -440,6 +466,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Shaanan Cohney</b></sub> |             <sub style="font-size:14px"><b>Shaanan Cohney</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/m-tanner-dev0> |         <a href=https://github.com/m-tanner-dev0> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/97977342?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Tanner/> |             <img src=https://avatars.githubusercontent.com/u/97977342?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Tanner/> | ||||||
| @ -454,8 +482,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Teteros</b></sub> |             <sub style="font-size:14px"><b>Teteros</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/gitter-badger> |         <a href=https://github.com/gitter-badger> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/8518239?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=The Gitter Badger/> |             <img src=https://avatars.githubusercontent.com/u/8518239?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=The Gitter Badger/> | ||||||
| @ -484,6 +510,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>Yang Bin</b></sub> |             <sub style="font-size:14px"><b>Yang Bin</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/zekker6> |         <a href=https://github.com/zekker6> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/1367798?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Zakhar Bessarab/> |             <img src=https://avatars.githubusercontent.com/u/1367798?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Zakhar Bessarab/> | ||||||
| @ -498,8 +526,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b>ZiYuan</b></sub> |             <sub style="font-size:14px"><b>ZiYuan</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/bravechamp> |         <a href=https://github.com/bravechamp> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/48980452?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=bravechamp/> |             <img src=https://avatars.githubusercontent.com/u/48980452?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=bravechamp/> | ||||||
| @ -528,6 +554,8 @@ make build | |||||||
|             <sub style="font-size:14px"><b>ignoramous</b></sub> |             <sub style="font-size:14px"><b>ignoramous</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/lion24> |         <a href=https://github.com/lion24> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/1382102?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=lion24/> |             <img src=https://avatars.githubusercontent.com/u/1382102?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=lion24/> | ||||||
| @ -542,8 +570,6 @@ make build | |||||||
|             <sub style="font-size:14px"><b>pernila</b></sub> |             <sub style="font-size:14px"><b>pernila</b></sub> | ||||||
|         </a> |         </a> | ||||||
|     </td> |     </td> | ||||||
| </tr> |  | ||||||
| <tr> |  | ||||||
|     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> |     <td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0"> | ||||||
|         <a href=https://github.com/Wakeful-Cloud> |         <a href=https://github.com/Wakeful-Cloud> | ||||||
|             <img src=https://avatars.githubusercontent.com/u/38930607?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Wakeful-Cloud/> |             <img src=https://avatars.githubusercontent.com/u/38930607?v=4 width="100;"  style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Wakeful-Cloud/> | ||||||
|  | |||||||
							
								
								
									
										27
									
								
								acls.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								acls.go
									
									
									
									
									
								
							| @ -2,6 +2,7 @@ package headscale | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| @ -251,8 +252,27 @@ func expandAlias( | |||||||
| 	if strings.HasPrefix(alias, "tag:") { | 	if strings.HasPrefix(alias, "tag:") { | ||||||
| 		owners, err := expandTagOwners(aclPolicy, alias, stripEmailDomain) | 		owners, err := expandTagOwners(aclPolicy, alias, stripEmailDomain) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | 			if errors.Is(err, errInvalidTag) { | ||||||
|  | 				for _, machine := range machines { | ||||||
|  | 					for _, t := range machine.ForcedTags { | ||||||
|  | 						if alias == t { | ||||||
|  | 							ips = append(ips, machine.IPAddresses.ToStringSlice()...) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if len(ips) == 0 { | ||||||
|  | 					return ips, fmt.Errorf( | ||||||
|  | 						"%w. %v isn't owned by a TagOwner and no forced tags are defined", | ||||||
|  | 						errInvalidTag, | ||||||
|  | 						alias, | ||||||
|  | 					) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				return ips, nil | ||||||
|  | 			} else { | ||||||
| 				return ips, err | 				return ips, err | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 		for _, namespace := range owners { | 		for _, namespace := range owners { | ||||||
| 			machines := filterMachinesByNamespace(machines, namespace) | 			machines := filterMachinesByNamespace(machines, namespace) | ||||||
| 			for _, machine := range machines { | 			for _, machine := range machines { | ||||||
| @ -312,7 +332,7 @@ func excludeCorrectlyTaggedNodes( | |||||||
| 	out := []Machine{} | 	out := []Machine{} | ||||||
| 	tags := []string{} | 	tags := []string{} | ||||||
| 	for tag, ns := range aclPolicy.TagOwners { | 	for tag, ns := range aclPolicy.TagOwners { | ||||||
| 		if containsString(ns, namespace) { | 		if contains(ns, namespace) { | ||||||
| 			tags = append(tags, tag) | 			tags = append(tags, tag) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -322,12 +342,15 @@ func excludeCorrectlyTaggedNodes( | |||||||
| 
 | 
 | ||||||
| 		found := false | 		found := false | ||||||
| 		for _, t := range hi.RequestTags { | 		for _, t := range hi.RequestTags { | ||||||
| 			if containsString(tags, t) { | 			if contains(tags, t) { | ||||||
| 				found = true | 				found = true | ||||||
| 
 | 
 | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		if len(machine.ForcedTags) > 0 { | ||||||
|  | 			found = true | ||||||
|  | 		} | ||||||
| 		if !found { | 		if !found { | ||||||
| 			out = append(out, machine) | 			out = append(out, machine) | ||||||
| 		} | 		} | ||||||
|  | |||||||
							
								
								
									
										79
									
								
								acls_test.go
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								acls_test.go
									
									
									
									
									
								
							| @ -1017,6 +1017,44 @@ func Test_expandAlias(t *testing.T) { | |||||||
| 			want:    []string{}, | 			want:    []string{}, | ||||||
| 			wantErr: true, | 			wantErr: true, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "Forced tag defined", | ||||||
|  | 			args: args{ | ||||||
|  | 				alias: "tag:hr-webserver", | ||||||
|  | 				machines: []Machine{ | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.1"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace:  Namespace{Name: "joe"}, | ||||||
|  | 						ForcedTags: []string{"tag:hr-webserver"}, | ||||||
|  | 					}, | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.2"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace:  Namespace{Name: "joe"}, | ||||||
|  | 						ForcedTags: []string{"tag:hr-webserver"}, | ||||||
|  | 					}, | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.3"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace: Namespace{Name: "marc"}, | ||||||
|  | 					}, | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.4"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace: Namespace{Name: "mickael"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				aclPolicy:        ACLPolicy{}, | ||||||
|  | 				stripEmailDomain: true, | ||||||
|  | 			}, | ||||||
|  | 			want:    []string{"100.64.0.1", "100.64.0.2"}, | ||||||
|  | 			wantErr: false, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "list host in namespace without correctly tagged servers", | 			name: "list host in namespace without correctly tagged servers", | ||||||
| 			args: args{ | 			args: args{ | ||||||
| @ -1143,6 +1181,47 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) { | |||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "exclude nodes with valid tags and with forced tags", | ||||||
|  | 			args: args{ | ||||||
|  | 				aclPolicy: ACLPolicy{ | ||||||
|  | 					TagOwners: TagOwners{"tag:accountant-webserver": []string{"joe"}}, | ||||||
|  | 				}, | ||||||
|  | 				nodes: []Machine{ | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.1"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace: Namespace{Name: "joe"}, | ||||||
|  | 						HostInfo: HostInfo{ | ||||||
|  | 							OS:          "centos", | ||||||
|  | 							Hostname:    "foo", | ||||||
|  | 							RequestTags: []string{"tag:accountant-webserver"}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.2"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace:  Namespace{Name: "joe"}, | ||||||
|  | 						ForcedTags: []string{"tag:accountant-webserver"}, | ||||||
|  | 					}, | ||||||
|  | 					{ | ||||||
|  | 						IPAddresses: MachineAddresses{ | ||||||
|  | 							netaddr.MustParseIP("100.64.0.4"), | ||||||
|  | 						}, | ||||||
|  | 						Namespace: Namespace{Name: "joe"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				namespace: "joe", | ||||||
|  | 			}, | ||||||
|  | 			want: []Machine{ | ||||||
|  | 				{ | ||||||
|  | 					IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, | ||||||
|  | 					Namespace:   Namespace{Name: "joe"}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "all nodes have invalid tags, don't exclude them", | 			name: "all nodes have invalid tags, don't exclude them", | ||||||
| 			args: args{ | 			args: args{ | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								app.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								app.go
									
									
									
									
									
								
							| @ -119,6 +119,10 @@ type OIDCConfig struct { | |||||||
| 	Issuer           string | 	Issuer           string | ||||||
| 	ClientID         string | 	ClientID         string | ||||||
| 	ClientSecret     string | 	ClientSecret     string | ||||||
|  | 	Scope            []string | ||||||
|  | 	ExtraParams      map[string]string | ||||||
|  | 	AllowedDomains   []string | ||||||
|  | 	AllowedUsers     []string | ||||||
| 	StripEmaildomain bool | 	StripEmaildomain bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -292,11 +296,13 @@ func (h *Headscale) expireEphemeralNodesWorker() { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		expiredFound := false | ||||||
| 		for _, machine := range machines { | 		for _, machine := range machines { | ||||||
| 			if machine.AuthKey != nil && machine.LastSeen != nil && | 			if machine.AuthKey != nil && machine.LastSeen != nil && | ||||||
| 				machine.AuthKey.Ephemeral && | 				machine.AuthKey.Ephemeral && | ||||||
| 				time.Now(). | 				time.Now(). | ||||||
| 					After(machine.LastSeen.Add(h.cfg.EphemeralNodeInactivityTimeout)) { | 					After(machine.LastSeen.Add(h.cfg.EphemeralNodeInactivityTimeout)) { | ||||||
|  | 				expiredFound = true | ||||||
| 				log.Info(). | 				log.Info(). | ||||||
| 					Str("machine", machine.Hostname). | 					Str("machine", machine.Hostname). | ||||||
| 					Msg("Ephemeral client removed from database") | 					Msg("Ephemeral client removed from database") | ||||||
| @ -311,14 +317,17 @@ func (h *Headscale) expireEphemeralNodesWorker() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if expiredFound { | ||||||
| 			h.setLastStateChangeToNow(namespace.Name) | 			h.setLastStateChangeToNow(namespace.Name) | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context, | func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context, | ||||||
| 	req interface{}, | 	req interface{}, | ||||||
| 	info *grpc.UnaryServerInfo, | 	info *grpc.UnaryServerInfo, | ||||||
| 	handler grpc.UnaryHandler) (interface{}, error) { | 	handler grpc.UnaryHandler, | ||||||
|  | ) (interface{}, error) { | ||||||
| 	// Check if the request is coming from the on-server client. | 	// Check if the request is coming from the on-server client. | ||||||
| 	// This is not secure, but it is to maintain maintainability | 	// This is not secure, but it is to maintain maintainability | ||||||
| 	// with the "legacy" database-based client | 	// with the "legacy" database-based client | ||||||
|  | |||||||
| @ -13,12 +13,14 @@ import ( | |||||||
| 	"github.com/pterm/pterm" | 	"github.com/pterm/pterm" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	"google.golang.org/grpc/status" | 	"google.golang.org/grpc/status" | ||||||
|  | 	"inet.af/netaddr" | ||||||
| 	"tailscale.com/types/key" | 	"tailscale.com/types/key" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func init() { | func init() { | ||||||
| 	rootCmd.AddCommand(nodeCmd) | 	rootCmd.AddCommand(nodeCmd) | ||||||
| 	listNodesCmd.Flags().StringP("namespace", "n", "", "Filter by namespace") | 	listNodesCmd.Flags().StringP("namespace", "n", "", "Filter by namespace") | ||||||
|  | 	listNodesCmd.Flags().BoolP("tags", "t", false, "Show tags") | ||||||
| 	nodeCmd.AddCommand(listNodesCmd) | 	nodeCmd.AddCommand(listNodesCmd) | ||||||
| 
 | 
 | ||||||
| 	registerNodeCmd.Flags().StringP("namespace", "n", "", "Namespace") | 	registerNodeCmd.Flags().StringP("namespace", "n", "", "Namespace") | ||||||
| @ -53,6 +55,31 @@ func init() { | |||||||
| 		log.Fatalf(err.Error()) | 		log.Fatalf(err.Error()) | ||||||
| 	} | 	} | ||||||
| 	nodeCmd.AddCommand(deleteNodeCmd) | 	nodeCmd.AddCommand(deleteNodeCmd) | ||||||
|  | 
 | ||||||
|  | 	moveNodeCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||||
|  | 
 | ||||||
|  | 	err = moveNodeCmd.MarkFlagRequired("identifier") | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	moveNodeCmd.Flags().StringP("namespace", "n", "", "New namespace") | ||||||
|  | 
 | ||||||
|  | 	err = moveNodeCmd.MarkFlagRequired("namespace") | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf(err.Error()) | ||||||
|  | 	} | ||||||
|  | 	nodeCmd.AddCommand(moveNodeCmd) | ||||||
|  | 
 | ||||||
|  | 	tagCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||||
|  | 
 | ||||||
|  | 	err = tagCmd.MarkFlagRequired("identifier") | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf(err.Error()) | ||||||
|  | 	} | ||||||
|  | 	tagCmd.Flags(). | ||||||
|  | 		StringSliceP("tags", "t", []string{}, "List of tags to add to the node") | ||||||
|  | 	nodeCmd.AddCommand(tagCmd) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var nodeCmd = &cobra.Command{ | var nodeCmd = &cobra.Command{ | ||||||
| @ -123,6 +150,12 @@ var listNodesCmd = &cobra.Command{ | |||||||
| 
 | 
 | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 		showTags, err := cmd.Flags().GetBool("tags") | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput(err, fmt.Sprintf("Error getting tags flag: %s", err), output) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		ctx, client, conn, cancel := getHeadscaleCLIClient() | 		ctx, client, conn, cancel := getHeadscaleCLIClient() | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| @ -149,7 +182,7 @@ var listNodesCmd = &cobra.Command{ | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		tableData, err := nodesToPtables(namespace, response.Machines) | 		tableData, err := nodesToPtables(namespace, showTags, response.Machines) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output) | 			ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output) | ||||||
| 
 | 
 | ||||||
| @ -351,15 +384,88 @@ var deleteNodeCmd = &cobra.Command{ | |||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var moveNodeCmd = &cobra.Command{ | ||||||
|  | 	Use:     "move", | ||||||
|  | 	Short:   "Move node to another namespace", | ||||||
|  | 	Aliases: []string{"mv"}, | ||||||
|  | 	Run: func(cmd *cobra.Command, args []string) { | ||||||
|  | 		output, _ := cmd.Flags().GetString("output") | ||||||
|  | 
 | ||||||
|  | 		identifier, err := cmd.Flags().GetUint64("identifier") | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf("Error converting ID to integer: %s", err), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		namespace, err := cmd.Flags().GetString("namespace") | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf("Error getting namespace: %s", err), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		ctx, client, conn, cancel := getHeadscaleCLIClient() | ||||||
|  | 		defer cancel() | ||||||
|  | 		defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 		getRequest := &v1.GetMachineRequest{ | ||||||
|  | 			MachineId: identifier, | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		_, err = client.GetMachine(ctx, getRequest) | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf( | ||||||
|  | 					"Error getting node: %s", | ||||||
|  | 					status.Convert(err).Message(), | ||||||
|  | 				), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		moveRequest := &v1.MoveMachineRequest{ | ||||||
|  | 			MachineId: identifier, | ||||||
|  | 			Namespace: namespace, | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		moveResponse, err := client.MoveMachine(ctx, moveRequest) | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf( | ||||||
|  | 					"Error moving node: %s", | ||||||
|  | 					status.Convert(err).Message(), | ||||||
|  | 				), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		SuccessOutput(moveResponse.Machine, "Node moved to another namespace", output) | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func nodesToPtables( | func nodesToPtables( | ||||||
| 	currentNamespace string, | 	currentNamespace string, | ||||||
|  | 	showTags bool, | ||||||
| 	machines []*v1.Machine, | 	machines []*v1.Machine, | ||||||
| ) (pterm.TableData, error) { | ) (pterm.TableData, error) { | ||||||
| 	tableData := pterm.TableData{ | 	tableHeader := []string{ | ||||||
| 		{ |  | ||||||
| 		"ID", | 		"ID", | ||||||
| 			"Hostname", | 		"Name", | ||||||
| 			"Friendly name", |  | ||||||
| 		"NodeKey", | 		"NodeKey", | ||||||
| 		"Namespace", | 		"Namespace", | ||||||
| 		"IP addresses", | 		"IP addresses", | ||||||
| @ -367,8 +473,15 @@ func nodesToPtables( | |||||||
| 		"Last seen", | 		"Last seen", | ||||||
| 		"Online", | 		"Online", | ||||||
| 		"Expired", | 		"Expired", | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
|  | 	if showTags { | ||||||
|  | 		tableHeader = append(tableHeader, []string{ | ||||||
|  | 			"ForcedTags", | ||||||
|  | 			"InvalidTags", | ||||||
|  | 			"ValidTags", | ||||||
|  | 		}...) | ||||||
|  | 	} | ||||||
|  | 	tableData := pterm.TableData{tableHeader} | ||||||
| 
 | 
 | ||||||
| 	for _, machine := range machines { | 	for _, machine := range machines { | ||||||
| 		var ephemeral bool | 		var ephemeral bool | ||||||
| @ -412,6 +525,26 @@ func nodesToPtables( | |||||||
| 			expired = pterm.LightRed("yes") | 			expired = pterm.LightRed("yes") | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		var forcedTags string | ||||||
|  | 		for _, tag := range machine.ForcedTags { | ||||||
|  | 			forcedTags += "," + tag | ||||||
|  | 		} | ||||||
|  | 		forcedTags = strings.TrimLeft(forcedTags, ",") | ||||||
|  | 		var invalidTags string | ||||||
|  | 		for _, tag := range machine.InvalidTags { | ||||||
|  | 			if !contains(machine.ForcedTags, tag) { | ||||||
|  | 				invalidTags += "," + pterm.LightRed(tag) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		invalidTags = strings.TrimLeft(invalidTags, ",") | ||||||
|  | 		var validTags string | ||||||
|  | 		for _, tag := range machine.ValidTags { | ||||||
|  | 			if !contains(machine.ForcedTags, tag) { | ||||||
|  | 				validTags += "," + pterm.LightGreen(tag) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		validTags = strings.TrimLeft(validTags, ",") | ||||||
|  | 
 | ||||||
| 		var namespace string | 		var namespace string | ||||||
| 		if currentNamespace == "" || (currentNamespace == machine.Namespace.Name) { | 		if currentNamespace == "" || (currentNamespace == machine.Namespace.Name) { | ||||||
| 			namespace = pterm.LightMagenta(machine.Namespace.Name) | 			namespace = pterm.LightMagenta(machine.Namespace.Name) | ||||||
| @ -419,22 +552,94 @@ func nodesToPtables( | |||||||
| 			// Shared into this namespace | 			// Shared into this namespace | ||||||
| 			namespace = pterm.LightYellow(machine.Namespace.Name) | 			namespace = pterm.LightYellow(machine.Namespace.Name) | ||||||
| 		} | 		} | ||||||
| 		tableData = append( | 
 | ||||||
| 			tableData, | 		var IPV4Address string | ||||||
| 			[]string{ | 		var IPV6Address string | ||||||
|  | 		for _, addr := range machine.IpAddresses { | ||||||
|  | 			if netaddr.MustParseIP(addr).Is4() { | ||||||
|  | 				IPV4Address = addr | ||||||
|  | 			} else { | ||||||
|  | 				IPV6Address = addr | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		nodeData := []string{ | ||||||
| 			strconv.FormatUint(machine.Id, headscale.Base10), | 			strconv.FormatUint(machine.Id, headscale.Base10), | ||||||
| 			machine.Name, | 			machine.Name, | ||||||
| 				machine.GivenName, |  | ||||||
| 			nodeKey.ShortString(), | 			nodeKey.ShortString(), | ||||||
| 			namespace, | 			namespace, | ||||||
| 				strings.Join(machine.IpAddresses, ", "), | 			strings.Join([]string{IPV4Address, IPV6Address}, ", "), | ||||||
| 			strconv.FormatBool(ephemeral), | 			strconv.FormatBool(ephemeral), | ||||||
| 			lastSeenTime, | 			lastSeenTime, | ||||||
| 			online, | 			online, | ||||||
| 			expired, | 			expired, | ||||||
| 			}, | 		} | ||||||
|  | 		if showTags { | ||||||
|  | 			nodeData = append(nodeData, []string{forcedTags, invalidTags, validTags}...) | ||||||
|  | 		} | ||||||
|  | 		tableData = append( | ||||||
|  | 			tableData, | ||||||
|  | 			nodeData, | ||||||
| 		) | 		) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return tableData, nil | 	return tableData, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | var tagCmd = &cobra.Command{ | ||||||
|  | 	Use:     "tag", | ||||||
|  | 	Short:   "Manage the tags of a node", | ||||||
|  | 	Aliases: []string{"tags", "t"}, | ||||||
|  | 	Run: func(cmd *cobra.Command, args []string) { | ||||||
|  | 		output, _ := cmd.Flags().GetString("output") | ||||||
|  | 		ctx, client, conn, cancel := getHeadscaleCLIClient() | ||||||
|  | 		defer cancel() | ||||||
|  | 		defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 		// retrieve flags from CLI | ||||||
|  | 		identifier, err := cmd.Flags().GetUint64("identifier") | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf("Error converting ID to integer: %s", err), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		tagsToSet, err := cmd.Flags().GetStringSlice("tags") | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf("Error retrieving list of tags to add to machine, %v", err), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Sending tags to machine | ||||||
|  | 		request := &v1.SetTagsRequest{ | ||||||
|  | 			MachineId: identifier, | ||||||
|  | 			Tags:      tagsToSet, | ||||||
|  | 		} | ||||||
|  | 		resp, err := client.SetTags(ctx, request) | ||||||
|  | 		if err != nil { | ||||||
|  | 			ErrorOutput( | ||||||
|  | 				err, | ||||||
|  | 				fmt.Sprintf("Error while sending tags to headscale: %s", err), | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if resp != nil { | ||||||
|  | 			SuccessOutput( | ||||||
|  | 				resp.GetMachine(), | ||||||
|  | 				"Machine updated", | ||||||
|  | 				output, | ||||||
|  | 			) | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  | |||||||
| @ -24,6 +24,8 @@ func init() { | |||||||
| 	enableRouteCmd.Flags(). | 	enableRouteCmd.Flags(). | ||||||
| 		StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to enable") | 		StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to enable") | ||||||
| 	enableRouteCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | 	enableRouteCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||||
|  | 	enableRouteCmd.Flags().BoolP("all", "a", false, "All routes from host") | ||||||
|  | 
 | ||||||
| 	err = enableRouteCmd.MarkFlagRequired("identifier") | 	err = enableRouteCmd.MarkFlagRequired("identifier") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatalf(err.Error()) | 		log.Fatalf(err.Error()) | ||||||
| @ -125,7 +127,32 @@ omit the route you do not want to enable. | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		routes, err := cmd.Flags().GetStringSlice("route") | 		ctx, client, conn, cancel := getHeadscaleCLIClient() | ||||||
|  | 		defer cancel() | ||||||
|  | 		defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 		var routes []string | ||||||
|  | 
 | ||||||
|  | 		isAll, _ := cmd.Flags().GetBool("all") | ||||||
|  | 		if isAll { | ||||||
|  | 			response, err := client.GetMachineRoute(ctx, &v1.GetMachineRouteRequest{ | ||||||
|  | 				MachineId: machineID, | ||||||
|  | 			}) | ||||||
|  | 			if err != nil { | ||||||
|  | 				ErrorOutput( | ||||||
|  | 					err, | ||||||
|  | 					fmt.Sprintf( | ||||||
|  | 						"Cannot get machine routes: %s\n", | ||||||
|  | 						status.Convert(err).Message(), | ||||||
|  | 					), | ||||||
|  | 					output, | ||||||
|  | 				) | ||||||
|  | 
 | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			routes = response.GetRoutes().GetAdvertisedRoutes() | ||||||
|  | 		} else { | ||||||
|  | 			routes, err = cmd.Flags().GetStringSlice("route") | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				ErrorOutput( | 				ErrorOutput( | ||||||
| 					err, | 					err, | ||||||
| @ -135,10 +162,7 @@ omit the route you do not want to enable. | |||||||
| 
 | 
 | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 
 | 		} | ||||||
| 		ctx, client, conn, cancel := getHeadscaleCLIClient() |  | ||||||
| 		defer cancel() |  | ||||||
| 		defer conn.Close() |  | ||||||
| 
 | 
 | ||||||
| 		request := &v1.EnableMachineRoutesRequest{ | 		request := &v1.EnableMachineRoutesRequest{ | ||||||
| 			MachineId: machineID, | 			MachineId: machineID, | ||||||
|  | |||||||
| @ -10,10 +10,12 @@ import ( | |||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | 	"reflect" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/coreos/go-oidc/v3/oidc" | ||||||
| 	"github.com/juanfont/headscale" | 	"github.com/juanfont/headscale" | ||||||
| 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| @ -67,6 +69,7 @@ func LoadConfig(path string) error { | |||||||
| 	viper.SetDefault("cli.timeout", "5s") | 	viper.SetDefault("cli.timeout", "5s") | ||||||
| 	viper.SetDefault("cli.insecure", false) | 	viper.SetDefault("cli.insecure", false) | ||||||
| 
 | 
 | ||||||
|  | 	viper.SetDefault("oidc.scope", []string{oidc.ScopeOpenID, "profile", "email"}) | ||||||
| 	viper.SetDefault("oidc.strip_email_domain", true) | 	viper.SetDefault("oidc.strip_email_domain", true) | ||||||
| 
 | 
 | ||||||
| 	if err := viper.ReadInConfig(); err != nil { | 	if err := viper.ReadInConfig(); err != nil { | ||||||
| @ -127,7 +130,8 @@ func GetDERPConfig() headscale.DERPConfig { | |||||||
| 	stunAddr := viper.GetString("derp.server.stun_listen_addr") | 	stunAddr := viper.GetString("derp.server.stun_listen_addr") | ||||||
| 
 | 
 | ||||||
| 	if serverEnabled && stunAddr == "" { | 	if serverEnabled && stunAddr == "" { | ||||||
| 		log.Fatal().Msg("derp.server.stun_listen_addr must be set if derp.server.enabled is true") | 		log.Fatal(). | ||||||
|  | 			Msg("derp.server.stun_listen_addr must be set if derp.server.enabled is true") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	urlStrs := viper.GetStringSlice("derp.urls") | 	urlStrs := viper.GetStringSlice("derp.urls") | ||||||
| @ -367,6 +371,10 @@ func getHeadscaleConfig() headscale.Config { | |||||||
| 			Issuer:           viper.GetString("oidc.issuer"), | 			Issuer:           viper.GetString("oidc.issuer"), | ||||||
| 			ClientID:         viper.GetString("oidc.client_id"), | 			ClientID:         viper.GetString("oidc.client_id"), | ||||||
| 			ClientSecret:     viper.GetString("oidc.client_secret"), | 			ClientSecret:     viper.GetString("oidc.client_secret"), | ||||||
|  | 			Scope:            viper.GetStringSlice("oidc.scope"), | ||||||
|  | 			ExtraParams:      viper.GetStringMapString("oidc.extra_params"), | ||||||
|  | 			AllowedDomains:   viper.GetStringSlice("oidc.allowed_domains"), | ||||||
|  | 			AllowedUsers:     viper.GetStringSlice("oidc.allowed_users"), | ||||||
| 			StripEmaildomain: viper.GetBool("oidc.strip_email_domain"), | 			StripEmaildomain: viper.GetBool("oidc.strip_email_domain"), | ||||||
| 		}, | 		}, | ||||||
| 
 | 
 | ||||||
| @ -563,3 +571,13 @@ func GetFileMode(key string) fs.FileMode { | |||||||
| 
 | 
 | ||||||
| 	return fs.FileMode(mode) | 	return fs.FileMode(mode) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func contains[T string](ts []T, t T) bool { | ||||||
|  | 	for _, v := range ts { | ||||||
|  | 		if reflect.DeepEqual(v, t) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | |||||||
| @ -214,6 +214,21 @@ unix_socket_permission: "0770" | |||||||
| #   client_id: "your-oidc-client-id" | #   client_id: "your-oidc-client-id" | ||||||
| #   client_secret: "your-oidc-client-secret" | #   client_secret: "your-oidc-client-secret" | ||||||
| # | # | ||||||
|  | #   Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query | ||||||
|  | #   parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email". | ||||||
|  | # | ||||||
|  | #   scope: ["openid", "profile", "email", "custom"] | ||||||
|  | #   extra_params: | ||||||
|  | #     domain_hint: example.com | ||||||
|  | # | ||||||
|  | #   List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the | ||||||
|  | #   authentication request will be rejected. | ||||||
|  | # | ||||||
|  | #   allowed_domains: | ||||||
|  | #     - example.com | ||||||
|  | #   allowed_users: | ||||||
|  | #     - alice@example.com | ||||||
|  | # | ||||||
| #   If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed. | #   If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed. | ||||||
| #   This will transform `first-name.last-name@example.com` to the namespace `first-name.last-name` | #   This will transform `first-name.last-name@example.com` to the namespace `first-name.last-name` | ||||||
| #   If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following | #   If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following | ||||||
|  | |||||||
| @ -107,7 +107,10 @@ func (h *Headscale) DERPHandler(ctx *gin.Context) { | |||||||
| 	hijacker, ok := ctx.Writer.(http.Hijacker) | 	hijacker, ok := ctx.Writer.(http.Hijacker) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		log.Error().Caller().Msg("DERP requires Hijacker interface from Gin") | 		log.Error().Caller().Msg("DERP requires Hijacker interface from Gin") | ||||||
| 		ctx.String(http.StatusInternalServerError, "HTTP does not support general TCP support") | 		ctx.String( | ||||||
|  | 			http.StatusInternalServerError, | ||||||
|  | 			"HTTP does not support general TCP support", | ||||||
|  | 		) | ||||||
| 
 | 
 | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @ -115,7 +118,10 @@ func (h *Headscale) DERPHandler(ctx *gin.Context) { | |||||||
| 	netConn, conn, err := hijacker.Hijack() | 	netConn, conn, err := hijacker.Hijack() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Error().Caller().Err(err).Msgf("Hijack failed") | 		log.Error().Caller().Err(err).Msgf("Hijack failed") | ||||||
| 		ctx.String(http.StatusInternalServerError, "HTTP does not support general TCP support") | 		ctx.String( | ||||||
|  | 			http.StatusInternalServerError, | ||||||
|  | 			"HTTP does not support general TCP support", | ||||||
|  | 		) | ||||||
| 
 | 
 | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @ -163,7 +169,10 @@ func (h *Headscale) DERPBootstrapDNSHandler(ctx *gin.Context) { | |||||||
| 		for _, node := range region.Nodes { // we don't care if we override some nodes | 		for _, node := range region.Nodes { // we don't care if we override some nodes | ||||||
| 			addrs, err := r.LookupIP(resolvCtx, "ip", node.HostName) | 			addrs, err := r.LookupIP(resolvCtx, "ip", node.HostName) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				log.Trace().Caller().Err(err).Msgf("bootstrap DNS lookup failed %q", node.HostName) | 				log.Trace(). | ||||||
|  | 					Caller(). | ||||||
|  | 					Err(err). | ||||||
|  | 					Msgf("bootstrap DNS lookup failed %q", node.HostName) | ||||||
| 
 | 
 | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  | |||||||
							
								
								
									
										47
									
								
								docs/acls.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								docs/acls.md
									
									
									
									
									
								
							| @ -5,12 +5,16 @@ ACL's are the most useful). | |||||||
| 
 | 
 | ||||||
| We have a small company with a boss, an admin, two developers and an intern. | We have a small company with a boss, an admin, two developers and an intern. | ||||||
| 
 | 
 | ||||||
| The boss should have access to all servers but not to the users hosts. Admin | The boss should have access to all servers but not to the user's hosts. Admin | ||||||
| should also have access to all hosts except that their permissions should be | should also have access to all hosts except that their permissions should be | ||||||
| limited to maintaining the hosts (for example purposes). The developers can do | limited to maintaining the hosts (for example purposes). The developers can do | ||||||
| anything they want on dev hosts, but only watch on productions hosts. Intern | anything they want on dev hosts but only watch on productions hosts. Intern | ||||||
| can only interact with the development servers. | can only interact with the development servers. | ||||||
| 
 | 
 | ||||||
|  | There's an additional server that acts as a router, connecting the VPN users | ||||||
|  | to an internal network `10.20.0.0/16`. Developers must have access to those | ||||||
|  | internal resources. | ||||||
|  | 
 | ||||||
| Each user have at least a device connected to the network and we have some | Each user have at least a device connected to the network and we have some | ||||||
| servers. | servers. | ||||||
| 
 | 
 | ||||||
| @ -19,22 +23,19 @@ servers. | |||||||
| - app-server1.prod | - app-server1.prod | ||||||
| - app-server1.dev | - app-server1.dev | ||||||
| - billing.internal | - billing.internal | ||||||
|  | - router.internal | ||||||
| 
 | 
 | ||||||
| ## Setup of the network |  | ||||||
| 
 | 
 | ||||||
| Let's create the namespaces. Each user should have his own namespace. The users | ## ACL setup | ||||||
| here are represented as namespaces. |  | ||||||
| 
 | 
 | ||||||
| ```bash | Note: Namespaces will be created automatically when users authenticate with the | ||||||
| headscale namespaces create boss | Headscale server. | ||||||
| headscale namespaces create admin1 |  | ||||||
| headscale namespaces create dev1 |  | ||||||
| headscale namespaces create dev2 |  | ||||||
| headscale namespaces create intern1 |  | ||||||
| ``` |  | ||||||
| 
 | 
 | ||||||
| We don't need to create namespaces for the servers because the servers will be | ACLs could be written either on [huJSON](https://github.com/tailscale/hujson) | ||||||
| tagged. When registering the servers we will need to add the flag | or Yaml. Check the [test ACLs](../tests/acls) for further information. | ||||||
|  | 
 | ||||||
|  | When registering the servers we will need to add the flag | ||||||
| `--advertised-tags=tag:<tag1>,tag:<tag2>`, and the user (namespace) that is | `--advertised-tags=tag:<tag1>,tag:<tag2>`, and the user (namespace) that is | ||||||
| registering the server should be allowed to do it. Since anyone can add tags to | registering the server should be allowed to do it. Since anyone can add tags to | ||||||
| a server they can register, the check of the tags is done on headscale server | a server they can register, the check of the tags is done on headscale server | ||||||
| @ -70,6 +71,14 @@ Here are the ACL's to implement the same permissions as above: | |||||||
| 
 | 
 | ||||||
|     // interns cannot add servers |     // interns cannot add servers | ||||||
|   }, |   }, | ||||||
|  |   // hosts should be defined using its IP addresses and a subnet mask. | ||||||
|  |   // to define a single host, use a /32 mask. You cannot use DNS entries here, | ||||||
|  |   // as they're prone to be hijacked by replacing their IP addresses. | ||||||
|  |   // see https://github.com/tailscale/tailscale/issues/3800 for more information. | ||||||
|  |   "Hosts": { | ||||||
|  |     "postgresql.internal": "10.20.0.2/32", | ||||||
|  |     "webservers.internal": "10.20.10.1/29" | ||||||
|  |   }, | ||||||
|   "acls": [ |   "acls": [ | ||||||
|     // boss have access to all servers |     // boss have access to all servers | ||||||
|     { |     { | ||||||
| @ -108,6 +117,16 @@ Here are the ACL's to implement the same permissions as above: | |||||||
|         "tag:prod-app-servers:80,443" |         "tag:prod-app-servers:80,443" | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|  |     // developers have access to the internal network through the router. | ||||||
|  |     // the internal network is composed of HTTPS endpoints and Postgresql | ||||||
|  |     // database servers. There's an additional rule to allow traffic to be | ||||||
|  |     // forwarded to the internal subnet, 10.20.0.0/16. See this issue | ||||||
|  |     // https://github.com/juanfont/headscale/issues/502 | ||||||
|  |     { | ||||||
|  |       "action": "accept", | ||||||
|  |       "users": ["group:dev"], | ||||||
|  |       "ports": ["10.20.0.0/16:443,5432", "router.internal:0"] | ||||||
|  |     }, | ||||||
| 
 | 
 | ||||||
|     // servers should be able to talk to database. Database should not be able to initiate connections to |     // servers should be able to talk to database. Database should not be able to initiate connections to | ||||||
|     // applications servers |     // applications servers | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								docs/images/headscale-acl-network.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/images/headscale-acl-network.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 56 KiB | 
| @ -24,7 +24,7 @@ To create a API key, log into your `headscale` server and generate a key: | |||||||
| headscale apikeys create --expiration 90d | headscale apikeys create --expiration 90d | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Copy the output of the command and save it for later. Please not that you can not retrieve a key again, | Copy the output of the command and save it for later. Please note that you can not retrieve a key again, | ||||||
| if the key is lost, expire the old one, and create a new key. | if the key is lost, expire the old one, and create a new key. | ||||||
| 
 | 
 | ||||||
| To list the keys currently assosicated with the server: | To list the keys currently assosicated with the server: | ||||||
|  | |||||||
							
								
								
									
										42
									
								
								flake.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								flake.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | { | ||||||
|  |   "nodes": { | ||||||
|  |     "flake-utils": { | ||||||
|  |       "locked": { | ||||||
|  |         "lastModified": 1644229661, | ||||||
|  |         "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", | ||||||
|  |         "owner": "numtide", | ||||||
|  |         "repo": "flake-utils", | ||||||
|  |         "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", | ||||||
|  |         "type": "github" | ||||||
|  |       }, | ||||||
|  |       "original": { | ||||||
|  |         "owner": "numtide", | ||||||
|  |         "repo": "flake-utils", | ||||||
|  |         "type": "github" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "nixpkgs": { | ||||||
|  |       "locked": { | ||||||
|  |         "lastModified": 1647536224, | ||||||
|  |         "narHash": "sha256-SUIiz4DhMXgM7i+hvFWmLnhywr1WeRGIz+EIbwQQguM=", | ||||||
|  |         "owner": "NixOS", | ||||||
|  |         "repo": "nixpkgs", | ||||||
|  |         "rev": "dd8cebebbf0f9352501f251ac37b851d947f92dc", | ||||||
|  |         "type": "github" | ||||||
|  |       }, | ||||||
|  |       "original": { | ||||||
|  |         "id": "nixpkgs", | ||||||
|  |         "ref": "master", | ||||||
|  |         "type": "indirect" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "root": { | ||||||
|  |       "inputs": { | ||||||
|  |         "flake-utils": "flake-utils", | ||||||
|  |         "nixpkgs": "nixpkgs" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "root": "root", | ||||||
|  |   "version": 7 | ||||||
|  | } | ||||||
							
								
								
									
										148
									
								
								flake.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								flake.nix
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | |||||||
|  | { | ||||||
|  |   description = "headscale - Open Source Tailscale Control server"; | ||||||
|  | 
 | ||||||
|  |   inputs = { | ||||||
|  |     # TODO: Use unstable when Go 1.18 has made it in | ||||||
|  |     # https://nixpk.gs/pr-tracker.html?pr=164292 | ||||||
|  |     # nixpkgs.url = "nixpkgs/nixpkgs-unstable"; | ||||||
|  |     nixpkgs.url = "nixpkgs/master"; | ||||||
|  |     flake-utils.url = "github:numtide/flake-utils"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   outputs = { self, nixpkgs, flake-utils, ... }: | ||||||
|  |     let | ||||||
|  |       headscaleVersion = if (self ? shortRev) then self.shortRev else "dev"; | ||||||
|  |     in | ||||||
|  |     { | ||||||
|  |       overlay = final: prev: | ||||||
|  |         let | ||||||
|  |           pkgs = nixpkgs.legacyPackages.${prev.system}; | ||||||
|  |         in | ||||||
|  |         rec { | ||||||
|  |           golines = | ||||||
|  |             pkgs.buildGoModule rec { | ||||||
|  |               pname = "golines"; | ||||||
|  |               version = "0.9.0"; | ||||||
|  | 
 | ||||||
|  |               src = pkgs.fetchFromGitHub { | ||||||
|  |                 owner = "segmentio"; | ||||||
|  |                 repo = "golines"; | ||||||
|  |                 rev = "v${version}"; | ||||||
|  |                 sha256 = "sha256-BUXEg+4r9L/gqe4DhTlhN55P3jWt7ZyWFQycO6QePrw="; | ||||||
|  |               }; | ||||||
|  | 
 | ||||||
|  |               vendorSha256 = "sha256-sEzWUeVk5GB0H41wrp12P8sBWRjg0FHUX6ABDEEBqK8="; | ||||||
|  | 
 | ||||||
|  |               nativeBuildInputs = [ pkgs.installShellFiles ]; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |           protoc-gen-grpc-gateway = | ||||||
|  |             pkgs.buildGoModule rec { | ||||||
|  |               pname = "grpc-gateway"; | ||||||
|  |               version = "2.8.0"; | ||||||
|  | 
 | ||||||
|  |               src = pkgs.fetchFromGitHub { | ||||||
|  |                 owner = "grpc-ecosystem"; | ||||||
|  |                 repo = "grpc-gateway"; | ||||||
|  |                 rev = "v${version}"; | ||||||
|  |                 sha256 = "sha256-8eBBBYJ+tBjB2fgPMX/ZlbN3eeS75e8TAZYOKXs6hcg="; | ||||||
|  |               }; | ||||||
|  | 
 | ||||||
|  |               vendorSha256 = "sha256-AW2Gn/mlZyLMwF+NpK59eiOmQrYWW/9HPjbunYc9Ij4="; | ||||||
|  | 
 | ||||||
|  |               nativeBuildInputs = [ pkgs.installShellFiles ]; | ||||||
|  | 
 | ||||||
|  |               subPackages = [ "protoc-gen-grpc-gateway" "protoc-gen-openapiv2" ]; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |           headscale = | ||||||
|  |             pkgs.buildGo118Module rec { | ||||||
|  |               pname = "headscale"; | ||||||
|  |               version = headscaleVersion; | ||||||
|  |               src = pkgs.lib.cleanSource self; | ||||||
|  | 
 | ||||||
|  |               # When updating go.mod or go.sum, a new sha will need to be calculated, | ||||||
|  |               # update this if you have a mismatch after doing a change to thos files. | ||||||
|  |               vendorSha256 = "sha256-bYEN0Rz7D1oJIIUjAHxdPB0CkVlb91f1lIQbucLnirg="; | ||||||
|  | 
 | ||||||
|  |               ldflags = [ "-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}" ]; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     } // flake-utils.lib.eachDefaultSystem | ||||||
|  |       (system: | ||||||
|  |         let | ||||||
|  |           pkgs = import nixpkgs { | ||||||
|  |             overlays = [ self.overlay ]; | ||||||
|  |             inherit system; | ||||||
|  |           }; | ||||||
|  |           buildDeps = with pkgs; [ git go_1_18 gnumake ]; | ||||||
|  |           devDeps = with pkgs; | ||||||
|  |             buildDeps ++ [ | ||||||
|  |               golangci-lint | ||||||
|  |               golines | ||||||
|  |               nodePackages.prettier | ||||||
|  | 
 | ||||||
|  |               # Protobuf dependencies | ||||||
|  |               protobuf | ||||||
|  |               protoc-gen-go | ||||||
|  |               protoc-gen-go-grpc | ||||||
|  |               protoc-gen-grpc-gateway | ||||||
|  |               buf | ||||||
|  |               clang-tools # clang-format | ||||||
|  |             ]; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |           # Add entry to build a docker image with headscale | ||||||
|  |           # caveat: only works on Linux | ||||||
|  |           # | ||||||
|  |           # Usage: | ||||||
|  |           # nix build .#headscale-docker | ||||||
|  |           # docker load < result | ||||||
|  |           headscale-docker = pkgs.dockerTools.buildLayeredImage { | ||||||
|  |             name = "headscale"; | ||||||
|  |             tag = headscaleVersion; | ||||||
|  |             contents = [ pkgs.headscale ]; | ||||||
|  |             config.Entrypoint = [ (pkgs.headscale + "/bin/headscale") ]; | ||||||
|  |           }; | ||||||
|  |         in | ||||||
|  |         rec { | ||||||
|  |           # `nix develop` | ||||||
|  |           devShell = pkgs.mkShell { buildInputs = devDeps; }; | ||||||
|  | 
 | ||||||
|  |           # `nix build` | ||||||
|  |           packages = with pkgs; { | ||||||
|  |             inherit headscale; | ||||||
|  |             inherit headscale-docker; | ||||||
|  |           }; | ||||||
|  | 
 | ||||||
|  |           defaultPackage = pkgs.headscale; | ||||||
|  | 
 | ||||||
|  |           # `nix run` | ||||||
|  |           apps.headscale = flake-utils.lib.mkApp { | ||||||
|  |             drv = packages.headscale; | ||||||
|  |           }; | ||||||
|  |           defaultApp = apps.headscale; | ||||||
|  | 
 | ||||||
|  |           checks = { | ||||||
|  |             format = pkgs.runCommand "check-format" | ||||||
|  |               { | ||||||
|  |                 buildInputs = with pkgs; [ | ||||||
|  |                   gnumake | ||||||
|  |                   nixpkgs-fmt | ||||||
|  |                   golangci-lint | ||||||
|  |                   nodePackages.prettier | ||||||
|  |                   golines | ||||||
|  |                   clang-tools | ||||||
|  |                 ]; | ||||||
|  |               } '' | ||||||
|  |               ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ${./.} | ||||||
|  |               ${pkgs.golangci-lint}/bin/golangci-lint run --fix --timeout 10m | ||||||
|  |               ${pkgs.nodePackages.prettier}/bin/prettier --write '**/**.{ts,js,md,yaml,yml,sass,css,scss,html}' | ||||||
|  |               ${pkgs.golines}/bin/golines --max-len=88 --base-formatter=gofumpt -w ${./.} | ||||||
|  |               ${pkgs.clang-tools}/bin/clang-format -style="{BasedOnStyle: Google, IndentWidth: 4, AlignConsecutiveDeclarations: true, AlignConsecutiveAssignments: true, ColumnLimit: 0}" -i ${./.} | ||||||
|  |             ''; | ||||||
|  |           }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | } | ||||||
| @ -36,7 +36,7 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ | |||||||
| 	0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, | 	0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, | ||||||
| 	0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, | 	0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, | ||||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, | 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, | ||||||
| 	0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xb6, 0x14, 0x0a, 0x10, 0x48, 0x65, | 	0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xb1, 0x16, 0x0a, 0x10, 0x48, 0x65, | ||||||
| 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, | 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, | ||||||
| 	0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, | 	0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, | ||||||
| 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, | 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, | ||||||
| @ -119,91 +119,106 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ | |||||||
| 	0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, | 	0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, | ||||||
| 	0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, | 	0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, | ||||||
| 	0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | 	0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, | 	0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x74, 0x0a, 0x07, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, | ||||||
| 	0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, | 	0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, | ||||||
| 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, | 	0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, | ||||||
| 	0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, | 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, | ||||||
| 	0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, | 	0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, | ||||||
|  | 	0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, | ||||||
|  | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, | ||||||
|  | 	0x69, 0x64, 0x7d, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x80, 0x01, 0x0a, 0x0f, | ||||||
|  | 	0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, | ||||||
|  | 	0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, | ||||||
| 	0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, | 	0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, | ||||||
| 	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x18, | 	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | ||||||
| 	0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, | 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, | ||||||
| 	0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x7e, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, | 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, | ||||||
| 	0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, | 	0xe4, 0x93, 0x02, 0x1a, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, | ||||||
| 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, | 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x7e, | ||||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, | 	0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, | ||||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, | 	0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, | ||||||
| 	0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, | 	0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, | ||||||
| 	0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x2a, 0x1c, 0x2f, 0x61, 0x70, 0x69, | 	0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, | ||||||
| 	0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, | 	0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x85, 0x01, 0x0a, 0x0d, 0x45, 0x78, 0x70, | 	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, | ||||||
| 	0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, | 	0x2a, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, | 	0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x85, | ||||||
| 	0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, | 	0x01, 0x0a, 0x0d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||||
| 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, | 	0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, | ||||||
| 	0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, | 	0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, | ||||||
| 	0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, | 	0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, | ||||||
| 	0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, | 	0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, | 	0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, | ||||||
| 	0x12, 0x90, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, | 	0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x6e, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, | 	0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, | ||||||
| 	0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, | 	0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6e, 0x61, 0x6d, | ||||||
| 	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | 	0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, | ||||||
| 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, | 	0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, | ||||||
| 	0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, | 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, | ||||||
| 	0x93, 0x02, 0x30, 0x22, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, | 	0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, | 	0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, | ||||||
| 	0x7d, 0x2f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, | 	0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x2f, | ||||||
| 	0x6d, 0x65, 0x7d, 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, | 	0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, | ||||||
| 	0x6e, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, | 	0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, | ||||||
| 	0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, | 	0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, | ||||||
| 	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | 	0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, | ||||||
| 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, | ||||||
| 	0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, | 	0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, | ||||||
| 	0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, | 	0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, | ||||||
| 	0x69, 0x6e, 0x65, 0x12, 0x8b, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, | 	0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, | ||||||
| 	0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, | 	0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, | ||||||
| 	0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | 	0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x0b, 0x4d, 0x6f, | ||||||
| 	0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, | 	0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, | ||||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, | 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, | ||||||
| 	0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, | 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, | ||||||
| 	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x61, | 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x4d, | ||||||
| 	0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, | ||||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, | 	0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, 0x26, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, | ||||||
| 	0x73, 0x12, 0x97, 0x01, 0x0a, 0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, |  | ||||||
| 	0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x68, 0x65, 0x61, 0x64, |  | ||||||
| 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, |  | ||||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, |  | ||||||
| 	0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, |  | ||||||
| 	0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, |  | ||||||
| 	0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, |  | ||||||
| 	0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, |  | ||||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||||
| 	0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x43, | 	0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x8b, | ||||||
| 	0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, | 	0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, | ||||||
| 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, | 	0x74, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, | ||||||
| 	0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, | 	0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, | ||||||
| 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, | 	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, | ||||||
| 	0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, | 	0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0e, 0x2f, 0x61, 0x70, 0x69, | 	0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, | ||||||
| 	0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, | 	0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, | ||||||
| 	0x0c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, | 	0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, | 	0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x97, 0x01, 0x0a, | ||||||
| 	0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, | 	0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, | ||||||
| 	0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, | 	0x75, 0x74, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, | ||||||
| 	0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, | 	0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x61, | 	0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, | ||||||
| 	0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, | 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, | ||||||
| 	0x69, 0x72, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, | 	0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, | ||||||
| 	0x69, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | 	0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, | ||||||
| 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, | 	0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, | 	0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, | ||||||
| 	0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, | 	0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, | ||||||
| 	0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, | 	0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||||
| 	0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, | 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, | ||||||
| 	0x65, 0x79, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, | 	0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, | ||||||
| 	0x2f, 0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, | 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, | ||||||
| 	0x61, 0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, | 	0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, | ||||||
| 	0x72, 0x6f, 0x74, 0x6f, 0x33, | 	0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, | ||||||
|  | 	0x70, 0x69, 0x6b, 0x65, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x69, | ||||||
|  | 	0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, | ||||||
|  | 	0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, | ||||||
|  | 	0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, | ||||||
|  | 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, | ||||||
|  | 	0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, | ||||||
|  | 	0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, | ||||||
|  | 	0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x3a, 0x01, | ||||||
|  | 	0x2a, 0x12, 0x6a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, | ||||||
|  | 	0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, | ||||||
|  | 	0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, | ||||||
|  | 	0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, | ||||||
|  | 	0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, | ||||||
|  | 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, | ||||||
|  | 	0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x42, 0x29, 0x5a, | ||||||
|  | 	0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61, 0x6e, | ||||||
|  | 	0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x67, | ||||||
|  | 	0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var file_headscale_v1_headscale_proto_goTypes = []interface{}{ | var file_headscale_v1_headscale_proto_goTypes = []interface{}{ | ||||||
| @ -217,36 +232,40 @@ var file_headscale_v1_headscale_proto_goTypes = []interface{}{ | |||||||
| 	(*ListPreAuthKeysRequest)(nil),      // 7: headscale.v1.ListPreAuthKeysRequest | 	(*ListPreAuthKeysRequest)(nil),      // 7: headscale.v1.ListPreAuthKeysRequest | ||||||
| 	(*DebugCreateMachineRequest)(nil),   // 8: headscale.v1.DebugCreateMachineRequest | 	(*DebugCreateMachineRequest)(nil),   // 8: headscale.v1.DebugCreateMachineRequest | ||||||
| 	(*GetMachineRequest)(nil),           // 9: headscale.v1.GetMachineRequest | 	(*GetMachineRequest)(nil),           // 9: headscale.v1.GetMachineRequest | ||||||
| 	(*RegisterMachineRequest)(nil),      // 10: headscale.v1.RegisterMachineRequest | 	(*SetTagsRequest)(nil),              // 10: headscale.v1.SetTagsRequest | ||||||
| 	(*DeleteMachineRequest)(nil),        // 11: headscale.v1.DeleteMachineRequest | 	(*RegisterMachineRequest)(nil),      // 11: headscale.v1.RegisterMachineRequest | ||||||
| 	(*ExpireMachineRequest)(nil),        // 12: headscale.v1.ExpireMachineRequest | 	(*DeleteMachineRequest)(nil),        // 12: headscale.v1.DeleteMachineRequest | ||||||
| 	(*RenameMachineRequest)(nil),        // 13: headscale.v1.RenameMachineRequest | 	(*ExpireMachineRequest)(nil),        // 13: headscale.v1.ExpireMachineRequest | ||||||
| 	(*ListMachinesRequest)(nil),         // 14: headscale.v1.ListMachinesRequest | 	(*RenameMachineRequest)(nil),        // 14: headscale.v1.RenameMachineRequest | ||||||
| 	(*GetMachineRouteRequest)(nil),      // 15: headscale.v1.GetMachineRouteRequest | 	(*ListMachinesRequest)(nil),         // 15: headscale.v1.ListMachinesRequest | ||||||
| 	(*EnableMachineRoutesRequest)(nil),  // 16: headscale.v1.EnableMachineRoutesRequest | 	(*MoveMachineRequest)(nil),          // 16: headscale.v1.MoveMachineRequest | ||||||
| 	(*CreateApiKeyRequest)(nil),         // 17: headscale.v1.CreateApiKeyRequest | 	(*GetMachineRouteRequest)(nil),      // 17: headscale.v1.GetMachineRouteRequest | ||||||
| 	(*ExpireApiKeyRequest)(nil),         // 18: headscale.v1.ExpireApiKeyRequest | 	(*EnableMachineRoutesRequest)(nil),  // 18: headscale.v1.EnableMachineRoutesRequest | ||||||
| 	(*ListApiKeysRequest)(nil),          // 19: headscale.v1.ListApiKeysRequest | 	(*CreateApiKeyRequest)(nil),         // 19: headscale.v1.CreateApiKeyRequest | ||||||
| 	(*GetNamespaceResponse)(nil),        // 20: headscale.v1.GetNamespaceResponse | 	(*ExpireApiKeyRequest)(nil),         // 20: headscale.v1.ExpireApiKeyRequest | ||||||
| 	(*CreateNamespaceResponse)(nil),     // 21: headscale.v1.CreateNamespaceResponse | 	(*ListApiKeysRequest)(nil),          // 21: headscale.v1.ListApiKeysRequest | ||||||
| 	(*RenameNamespaceResponse)(nil),     // 22: headscale.v1.RenameNamespaceResponse | 	(*GetNamespaceResponse)(nil),        // 22: headscale.v1.GetNamespaceResponse | ||||||
| 	(*DeleteNamespaceResponse)(nil),     // 23: headscale.v1.DeleteNamespaceResponse | 	(*CreateNamespaceResponse)(nil),     // 23: headscale.v1.CreateNamespaceResponse | ||||||
| 	(*ListNamespacesResponse)(nil),      // 24: headscale.v1.ListNamespacesResponse | 	(*RenameNamespaceResponse)(nil),     // 24: headscale.v1.RenameNamespaceResponse | ||||||
| 	(*CreatePreAuthKeyResponse)(nil),    // 25: headscale.v1.CreatePreAuthKeyResponse | 	(*DeleteNamespaceResponse)(nil),     // 25: headscale.v1.DeleteNamespaceResponse | ||||||
| 	(*ExpirePreAuthKeyResponse)(nil),    // 26: headscale.v1.ExpirePreAuthKeyResponse | 	(*ListNamespacesResponse)(nil),      // 26: headscale.v1.ListNamespacesResponse | ||||||
| 	(*ListPreAuthKeysResponse)(nil),     // 27: headscale.v1.ListPreAuthKeysResponse | 	(*CreatePreAuthKeyResponse)(nil),    // 27: headscale.v1.CreatePreAuthKeyResponse | ||||||
| 	(*DebugCreateMachineResponse)(nil),  // 28: headscale.v1.DebugCreateMachineResponse | 	(*ExpirePreAuthKeyResponse)(nil),    // 28: headscale.v1.ExpirePreAuthKeyResponse | ||||||
| 	(*GetMachineResponse)(nil),          // 29: headscale.v1.GetMachineResponse | 	(*ListPreAuthKeysResponse)(nil),     // 29: headscale.v1.ListPreAuthKeysResponse | ||||||
| 	(*RegisterMachineResponse)(nil),     // 30: headscale.v1.RegisterMachineResponse | 	(*DebugCreateMachineResponse)(nil),  // 30: headscale.v1.DebugCreateMachineResponse | ||||||
| 	(*DeleteMachineResponse)(nil),       // 31: headscale.v1.DeleteMachineResponse | 	(*GetMachineResponse)(nil),          // 31: headscale.v1.GetMachineResponse | ||||||
| 	(*ExpireMachineResponse)(nil),       // 32: headscale.v1.ExpireMachineResponse | 	(*SetTagsResponse)(nil),             // 32: headscale.v1.SetTagsResponse | ||||||
| 	(*RenameMachineResponse)(nil),       // 33: headscale.v1.RenameMachineResponse | 	(*RegisterMachineResponse)(nil),     // 33: headscale.v1.RegisterMachineResponse | ||||||
| 	(*ListMachinesResponse)(nil),        // 34: headscale.v1.ListMachinesResponse | 	(*DeleteMachineResponse)(nil),       // 34: headscale.v1.DeleteMachineResponse | ||||||
| 	(*GetMachineRouteResponse)(nil),     // 35: headscale.v1.GetMachineRouteResponse | 	(*ExpireMachineResponse)(nil),       // 35: headscale.v1.ExpireMachineResponse | ||||||
| 	(*EnableMachineRoutesResponse)(nil), // 36: headscale.v1.EnableMachineRoutesResponse | 	(*RenameMachineResponse)(nil),       // 36: headscale.v1.RenameMachineResponse | ||||||
| 	(*CreateApiKeyResponse)(nil),        // 37: headscale.v1.CreateApiKeyResponse | 	(*ListMachinesResponse)(nil),        // 37: headscale.v1.ListMachinesResponse | ||||||
| 	(*ExpireApiKeyResponse)(nil),        // 38: headscale.v1.ExpireApiKeyResponse | 	(*MoveMachineResponse)(nil),         // 38: headscale.v1.MoveMachineResponse | ||||||
| 	(*ListApiKeysResponse)(nil),         // 39: headscale.v1.ListApiKeysResponse | 	(*GetMachineRouteResponse)(nil),     // 39: headscale.v1.GetMachineRouteResponse | ||||||
|  | 	(*EnableMachineRoutesResponse)(nil), // 40: headscale.v1.EnableMachineRoutesResponse | ||||||
|  | 	(*CreateApiKeyResponse)(nil),        // 41: headscale.v1.CreateApiKeyResponse | ||||||
|  | 	(*ExpireApiKeyResponse)(nil),        // 42: headscale.v1.ExpireApiKeyResponse | ||||||
|  | 	(*ListApiKeysResponse)(nil),         // 43: headscale.v1.ListApiKeysResponse | ||||||
| } | } | ||||||
| var file_headscale_v1_headscale_proto_depIdxs = []int32{ | var file_headscale_v1_headscale_proto_depIdxs = []int32{ | ||||||
| 	0,  // 0: headscale.v1.HeadscaleService.GetNamespace:input_type -> headscale.v1.GetNamespaceRequest | 	0,  // 0: headscale.v1.HeadscaleService.GetNamespace:input_type -> headscale.v1.GetNamespaceRequest | ||||||
| @ -259,38 +278,42 @@ var file_headscale_v1_headscale_proto_depIdxs = []int32{ | |||||||
| 	7,  // 7: headscale.v1.HeadscaleService.ListPreAuthKeys:input_type -> headscale.v1.ListPreAuthKeysRequest | 	7,  // 7: headscale.v1.HeadscaleService.ListPreAuthKeys:input_type -> headscale.v1.ListPreAuthKeysRequest | ||||||
| 	8,  // 8: headscale.v1.HeadscaleService.DebugCreateMachine:input_type -> headscale.v1.DebugCreateMachineRequest | 	8,  // 8: headscale.v1.HeadscaleService.DebugCreateMachine:input_type -> headscale.v1.DebugCreateMachineRequest | ||||||
| 	9,  // 9: headscale.v1.HeadscaleService.GetMachine:input_type -> headscale.v1.GetMachineRequest | 	9,  // 9: headscale.v1.HeadscaleService.GetMachine:input_type -> headscale.v1.GetMachineRequest | ||||||
| 	10, // 10: headscale.v1.HeadscaleService.RegisterMachine:input_type -> headscale.v1.RegisterMachineRequest | 	10, // 10: headscale.v1.HeadscaleService.SetTags:input_type -> headscale.v1.SetTagsRequest | ||||||
| 	11, // 11: headscale.v1.HeadscaleService.DeleteMachine:input_type -> headscale.v1.DeleteMachineRequest | 	11, // 11: headscale.v1.HeadscaleService.RegisterMachine:input_type -> headscale.v1.RegisterMachineRequest | ||||||
| 	12, // 12: headscale.v1.HeadscaleService.ExpireMachine:input_type -> headscale.v1.ExpireMachineRequest | 	12, // 12: headscale.v1.HeadscaleService.DeleteMachine:input_type -> headscale.v1.DeleteMachineRequest | ||||||
| 	13, // 13: headscale.v1.HeadscaleService.RenameMachine:input_type -> headscale.v1.RenameMachineRequest | 	13, // 13: headscale.v1.HeadscaleService.ExpireMachine:input_type -> headscale.v1.ExpireMachineRequest | ||||||
| 	14, // 14: headscale.v1.HeadscaleService.ListMachines:input_type -> headscale.v1.ListMachinesRequest | 	14, // 14: headscale.v1.HeadscaleService.RenameMachine:input_type -> headscale.v1.RenameMachineRequest | ||||||
| 	15, // 15: headscale.v1.HeadscaleService.GetMachineRoute:input_type -> headscale.v1.GetMachineRouteRequest | 	15, // 15: headscale.v1.HeadscaleService.ListMachines:input_type -> headscale.v1.ListMachinesRequest | ||||||
| 	16, // 16: headscale.v1.HeadscaleService.EnableMachineRoutes:input_type -> headscale.v1.EnableMachineRoutesRequest | 	16, // 16: headscale.v1.HeadscaleService.MoveMachine:input_type -> headscale.v1.MoveMachineRequest | ||||||
| 	17, // 17: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest | 	17, // 17: headscale.v1.HeadscaleService.GetMachineRoute:input_type -> headscale.v1.GetMachineRouteRequest | ||||||
| 	18, // 18: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest | 	18, // 18: headscale.v1.HeadscaleService.EnableMachineRoutes:input_type -> headscale.v1.EnableMachineRoutesRequest | ||||||
| 	19, // 19: headscale.v1.HeadscaleService.ListApiKeys:input_type -> headscale.v1.ListApiKeysRequest | 	19, // 19: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest | ||||||
| 	20, // 20: headscale.v1.HeadscaleService.GetNamespace:output_type -> headscale.v1.GetNamespaceResponse | 	20, // 20: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest | ||||||
| 	21, // 21: headscale.v1.HeadscaleService.CreateNamespace:output_type -> headscale.v1.CreateNamespaceResponse | 	21, // 21: headscale.v1.HeadscaleService.ListApiKeys:input_type -> headscale.v1.ListApiKeysRequest | ||||||
| 	22, // 22: headscale.v1.HeadscaleService.RenameNamespace:output_type -> headscale.v1.RenameNamespaceResponse | 	22, // 22: headscale.v1.HeadscaleService.GetNamespace:output_type -> headscale.v1.GetNamespaceResponse | ||||||
| 	23, // 23: headscale.v1.HeadscaleService.DeleteNamespace:output_type -> headscale.v1.DeleteNamespaceResponse | 	23, // 23: headscale.v1.HeadscaleService.CreateNamespace:output_type -> headscale.v1.CreateNamespaceResponse | ||||||
| 	24, // 24: headscale.v1.HeadscaleService.ListNamespaces:output_type -> headscale.v1.ListNamespacesResponse | 	24, // 24: headscale.v1.HeadscaleService.RenameNamespace:output_type -> headscale.v1.RenameNamespaceResponse | ||||||
| 	25, // 25: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse | 	25, // 25: headscale.v1.HeadscaleService.DeleteNamespace:output_type -> headscale.v1.DeleteNamespaceResponse | ||||||
| 	26, // 26: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse | 	26, // 26: headscale.v1.HeadscaleService.ListNamespaces:output_type -> headscale.v1.ListNamespacesResponse | ||||||
| 	27, // 27: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse | 	27, // 27: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse | ||||||
| 	28, // 28: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse | 	28, // 28: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse | ||||||
| 	29, // 29: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse | 	29, // 29: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse | ||||||
| 	30, // 30: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse | 	30, // 30: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse | ||||||
| 	31, // 31: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse | 	31, // 31: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse | ||||||
| 	32, // 32: headscale.v1.HeadscaleService.ExpireMachine:output_type -> headscale.v1.ExpireMachineResponse | 	32, // 32: headscale.v1.HeadscaleService.SetTags:output_type -> headscale.v1.SetTagsResponse | ||||||
| 	33, // 33: headscale.v1.HeadscaleService.RenameMachine:output_type -> headscale.v1.RenameMachineResponse | 	33, // 33: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse | ||||||
| 	34, // 34: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse | 	34, // 34: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse | ||||||
| 	35, // 35: headscale.v1.HeadscaleService.GetMachineRoute:output_type -> headscale.v1.GetMachineRouteResponse | 	35, // 35: headscale.v1.HeadscaleService.ExpireMachine:output_type -> headscale.v1.ExpireMachineResponse | ||||||
| 	36, // 36: headscale.v1.HeadscaleService.EnableMachineRoutes:output_type -> headscale.v1.EnableMachineRoutesResponse | 	36, // 36: headscale.v1.HeadscaleService.RenameMachine:output_type -> headscale.v1.RenameMachineResponse | ||||||
| 	37, // 37: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse | 	37, // 37: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse | ||||||
| 	38, // 38: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse | 	38, // 38: headscale.v1.HeadscaleService.MoveMachine:output_type -> headscale.v1.MoveMachineResponse | ||||||
| 	39, // 39: headscale.v1.HeadscaleService.ListApiKeys:output_type -> headscale.v1.ListApiKeysResponse | 	39, // 39: headscale.v1.HeadscaleService.GetMachineRoute:output_type -> headscale.v1.GetMachineRouteResponse | ||||||
| 	20, // [20:40] is the sub-list for method output_type | 	40, // 40: headscale.v1.HeadscaleService.EnableMachineRoutes:output_type -> headscale.v1.EnableMachineRoutesResponse | ||||||
| 	0,  // [0:20] is the sub-list for method input_type | 	41, // 41: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse | ||||||
|  | 	42, // 42: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse | ||||||
|  | 	43, // 43: headscale.v1.HeadscaleService.ListApiKeys:output_type -> headscale.v1.ListApiKeysResponse | ||||||
|  | 	22, // [22:44] is the sub-list for method output_type | ||||||
|  | 	0,  // [0:22] is the sub-list for method input_type | ||||||
| 	0,  // [0:0] is the sub-list for extension type_name | 	0,  // [0:0] is the sub-list for extension type_name | ||||||
| 	0,  // [0:0] is the sub-list for extension extendee | 	0,  // [0:0] is the sub-list for extension extendee | ||||||
| 	0,  // [0:0] is the sub-list for field type_name | 	0,  // [0:0] is the sub-list for field type_name | ||||||
|  | |||||||
| @ -449,6 +449,74 @@ func local_request_HeadscaleService_GetMachine_0(ctx context.Context, marshaler | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func request_HeadscaleService_SetTags_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||||
|  | 	var protoReq SetTagsRequest | ||||||
|  | 	var metadata runtime.ServerMetadata | ||||||
|  | 
 | ||||||
|  | 	newReader, berr := utilities.IOReaderFactory(req.Body) | ||||||
|  | 	if berr != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) | ||||||
|  | 	} | ||||||
|  | 	if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var ( | ||||||
|  | 		val string | ||||||
|  | 		ok  bool | ||||||
|  | 		err error | ||||||
|  | 		_   = err | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	val, ok = pathParams["machine_id"] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protoReq.MachineId, err = runtime.Uint64(val) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	msg, err := client.SetTags(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) | ||||||
|  | 	return msg, metadata, err | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func local_request_HeadscaleService_SetTags_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||||
|  | 	var protoReq SetTagsRequest | ||||||
|  | 	var metadata runtime.ServerMetadata | ||||||
|  | 
 | ||||||
|  | 	newReader, berr := utilities.IOReaderFactory(req.Body) | ||||||
|  | 	if berr != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) | ||||||
|  | 	} | ||||||
|  | 	if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var ( | ||||||
|  | 		val string | ||||||
|  | 		ok  bool | ||||||
|  | 		err error | ||||||
|  | 		_   = err | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	val, ok = pathParams["machine_id"] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protoReq.MachineId, err = runtime.Uint64(val) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	msg, err := server.SetTags(ctx, &protoReq) | ||||||
|  | 	return msg, metadata, err | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| var ( | var ( | ||||||
| 	filter_HeadscaleService_RegisterMachine_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} | 	filter_HeadscaleService_RegisterMachine_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} | ||||||
| ) | ) | ||||||
| @ -697,6 +765,76 @@ func local_request_HeadscaleService_ListMachines_0(ctx context.Context, marshale | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var ( | ||||||
|  | 	filter_HeadscaleService_MoveMachine_0 = &utilities.DoubleArray{Encoding: map[string]int{"machine_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func request_HeadscaleService_MoveMachine_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||||
|  | 	var protoReq MoveMachineRequest | ||||||
|  | 	var metadata runtime.ServerMetadata | ||||||
|  | 
 | ||||||
|  | 	var ( | ||||||
|  | 		val string | ||||||
|  | 		ok  bool | ||||||
|  | 		err error | ||||||
|  | 		_   = err | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	val, ok = pathParams["machine_id"] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protoReq.MachineId, err = runtime.Uint64(val) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := req.ParseForm(); err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) | ||||||
|  | 	} | ||||||
|  | 	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_HeadscaleService_MoveMachine_0); err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	msg, err := client.MoveMachine(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) | ||||||
|  | 	return msg, metadata, err | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func local_request_HeadscaleService_MoveMachine_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||||
|  | 	var protoReq MoveMachineRequest | ||||||
|  | 	var metadata runtime.ServerMetadata | ||||||
|  | 
 | ||||||
|  | 	var ( | ||||||
|  | 		val string | ||||||
|  | 		ok  bool | ||||||
|  | 		err error | ||||||
|  | 		_   = err | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	val, ok = pathParams["machine_id"] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protoReq.MachineId, err = runtime.Uint64(val) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := req.ParseForm(); err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) | ||||||
|  | 	} | ||||||
|  | 	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_HeadscaleService_MoveMachine_0); err != nil { | ||||||
|  | 		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	msg, err := server.MoveMachine(ctx, &protoReq) | ||||||
|  | 	return msg, metadata, err | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func request_HeadscaleService_GetMachineRoute_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | func request_HeadscaleService_GetMachineRoute_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||||
| 	var protoReq GetMachineRouteRequest | 	var protoReq GetMachineRouteRequest | ||||||
| 	var metadata runtime.ServerMetadata | 	var metadata runtime.ServerMetadata | ||||||
| @ -1141,6 +1279,29 @@ func RegisterHeadscaleServiceHandlerServer(ctx context.Context, mux *runtime.Ser | |||||||
| 
 | 
 | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
|  | 	mux.Handle("POST", pattern_HeadscaleService_SetTags_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
|  | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
|  | 		defer cancel() | ||||||
|  | 		var stream runtime.ServerTransportStream | ||||||
|  | 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) | ||||||
|  | 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) | ||||||
|  | 		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/SetTags", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/tags")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		resp, md, err := local_request_HeadscaleService_SetTags_0(rctx, inboundMarshaler, server, req, pathParams) | ||||||
|  | 		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) | ||||||
|  | 		ctx = runtime.NewServerMetadataContext(ctx, md) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		forward_HeadscaleService_SetTags_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) | ||||||
|  | 
 | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	mux.Handle("POST", pattern_HeadscaleService_RegisterMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | 	mux.Handle("POST", pattern_HeadscaleService_RegisterMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
| 		ctx, cancel := context.WithCancel(req.Context()) | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| @ -1256,6 +1417,29 @@ func RegisterHeadscaleServiceHandlerServer(ctx context.Context, mux *runtime.Ser | |||||||
| 
 | 
 | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
|  | 	mux.Handle("POST", pattern_HeadscaleService_MoveMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
|  | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
|  | 		defer cancel() | ||||||
|  | 		var stream runtime.ServerTransportStream | ||||||
|  | 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) | ||||||
|  | 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) | ||||||
|  | 		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/MoveMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/namespace")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		resp, md, err := local_request_HeadscaleService_MoveMachine_0(rctx, inboundMarshaler, server, req, pathParams) | ||||||
|  | 		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) | ||||||
|  | 		ctx = runtime.NewServerMetadataContext(ctx, md) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		forward_HeadscaleService_MoveMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) | ||||||
|  | 
 | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	mux.Handle("GET", pattern_HeadscaleService_GetMachineRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | 	mux.Handle("GET", pattern_HeadscaleService_GetMachineRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
| 		ctx, cancel := context.WithCancel(req.Context()) | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| @ -1612,6 +1796,26 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser | |||||||
| 
 | 
 | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
|  | 	mux.Handle("POST", pattern_HeadscaleService_SetTags_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
|  | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
|  | 		defer cancel() | ||||||
|  | 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) | ||||||
|  | 		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/SetTags", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/tags")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		resp, md, err := request_HeadscaleService_SetTags_0(rctx, inboundMarshaler, client, req, pathParams) | ||||||
|  | 		ctx = runtime.NewServerMetadataContext(ctx, md) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		forward_HeadscaleService_SetTags_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) | ||||||
|  | 
 | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	mux.Handle("POST", pattern_HeadscaleService_RegisterMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | 	mux.Handle("POST", pattern_HeadscaleService_RegisterMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
| 		ctx, cancel := context.WithCancel(req.Context()) | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| @ -1712,6 +1916,26 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser | |||||||
| 
 | 
 | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
|  | 	mux.Handle("POST", pattern_HeadscaleService_MoveMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
|  | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
|  | 		defer cancel() | ||||||
|  | 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) | ||||||
|  | 		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/MoveMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/namespace")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		resp, md, err := request_HeadscaleService_MoveMachine_0(rctx, inboundMarshaler, client, req, pathParams) | ||||||
|  | 		ctx = runtime.NewServerMetadataContext(ctx, md) | ||||||
|  | 		if err != nil { | ||||||
|  | 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		forward_HeadscaleService_MoveMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) | ||||||
|  | 
 | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	mux.Handle("GET", pattern_HeadscaleService_GetMachineRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | 	mux.Handle("GET", pattern_HeadscaleService_GetMachineRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||||
| 		ctx, cancel := context.WithCancel(req.Context()) | 		ctx, cancel := context.WithCancel(req.Context()) | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| @ -1836,6 +2060,8 @@ var ( | |||||||
| 
 | 
 | ||||||
| 	pattern_HeadscaleService_GetMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "machine", "machine_id"}, "")) | 	pattern_HeadscaleService_GetMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "machine", "machine_id"}, "")) | ||||||
| 
 | 
 | ||||||
|  | 	pattern_HeadscaleService_SetTags_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "tags"}, "")) | ||||||
|  | 
 | ||||||
| 	pattern_HeadscaleService_RegisterMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "machine", "register"}, "")) | 	pattern_HeadscaleService_RegisterMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "machine", "register"}, "")) | ||||||
| 
 | 
 | ||||||
| 	pattern_HeadscaleService_DeleteMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "machine", "machine_id"}, "")) | 	pattern_HeadscaleService_DeleteMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "machine", "machine_id"}, "")) | ||||||
| @ -1846,6 +2072,8 @@ var ( | |||||||
| 
 | 
 | ||||||
| 	pattern_HeadscaleService_ListMachines_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "machine"}, "")) | 	pattern_HeadscaleService_ListMachines_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "machine"}, "")) | ||||||
| 
 | 
 | ||||||
|  | 	pattern_HeadscaleService_MoveMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "namespace"}, "")) | ||||||
|  | 
 | ||||||
| 	pattern_HeadscaleService_GetMachineRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "routes"}, "")) | 	pattern_HeadscaleService_GetMachineRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "routes"}, "")) | ||||||
| 
 | 
 | ||||||
| 	pattern_HeadscaleService_EnableMachineRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "routes"}, "")) | 	pattern_HeadscaleService_EnableMachineRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "routes"}, "")) | ||||||
| @ -1878,6 +2106,8 @@ var ( | |||||||
| 
 | 
 | ||||||
| 	forward_HeadscaleService_GetMachine_0 = runtime.ForwardResponseMessage | 	forward_HeadscaleService_GetMachine_0 = runtime.ForwardResponseMessage | ||||||
| 
 | 
 | ||||||
|  | 	forward_HeadscaleService_SetTags_0 = runtime.ForwardResponseMessage | ||||||
|  | 
 | ||||||
| 	forward_HeadscaleService_RegisterMachine_0 = runtime.ForwardResponseMessage | 	forward_HeadscaleService_RegisterMachine_0 = runtime.ForwardResponseMessage | ||||||
| 
 | 
 | ||||||
| 	forward_HeadscaleService_DeleteMachine_0 = runtime.ForwardResponseMessage | 	forward_HeadscaleService_DeleteMachine_0 = runtime.ForwardResponseMessage | ||||||
| @ -1888,6 +2118,8 @@ var ( | |||||||
| 
 | 
 | ||||||
| 	forward_HeadscaleService_ListMachines_0 = runtime.ForwardResponseMessage | 	forward_HeadscaleService_ListMachines_0 = runtime.ForwardResponseMessage | ||||||
| 
 | 
 | ||||||
|  | 	forward_HeadscaleService_MoveMachine_0 = runtime.ForwardResponseMessage | ||||||
|  | 
 | ||||||
| 	forward_HeadscaleService_GetMachineRoute_0 = runtime.ForwardResponseMessage | 	forward_HeadscaleService_GetMachineRoute_0 = runtime.ForwardResponseMessage | ||||||
| 
 | 
 | ||||||
| 	forward_HeadscaleService_EnableMachineRoutes_0 = runtime.ForwardResponseMessage | 	forward_HeadscaleService_EnableMachineRoutes_0 = runtime.ForwardResponseMessage | ||||||
|  | |||||||
| @ -1,8 +1,4 @@ | |||||||
| // Code generated by protoc-gen-go-grpc. DO NOT EDIT. | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. | ||||||
| // versions: |  | ||||||
| // - protoc-gen-go-grpc v1.2.0 |  | ||||||
| // - protoc             (unknown) |  | ||||||
| // source: headscale/v1/headscale.proto |  | ||||||
| 
 | 
 | ||||||
| package v1 | package v1 | ||||||
| 
 | 
 | ||||||
| @ -35,11 +31,13 @@ type HeadscaleServiceClient interface { | |||||||
| 	// --- Machine start --- | 	// --- Machine start --- | ||||||
| 	DebugCreateMachine(ctx context.Context, in *DebugCreateMachineRequest, opts ...grpc.CallOption) (*DebugCreateMachineResponse, error) | 	DebugCreateMachine(ctx context.Context, in *DebugCreateMachineRequest, opts ...grpc.CallOption) (*DebugCreateMachineResponse, error) | ||||||
| 	GetMachine(ctx context.Context, in *GetMachineRequest, opts ...grpc.CallOption) (*GetMachineResponse, error) | 	GetMachine(ctx context.Context, in *GetMachineRequest, opts ...grpc.CallOption) (*GetMachineResponse, error) | ||||||
|  | 	SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error) | ||||||
| 	RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) | 	RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) | ||||||
| 	DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error) | 	DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error) | ||||||
| 	ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) | 	ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) | ||||||
| 	RenameMachine(ctx context.Context, in *RenameMachineRequest, opts ...grpc.CallOption) (*RenameMachineResponse, error) | 	RenameMachine(ctx context.Context, in *RenameMachineRequest, opts ...grpc.CallOption) (*RenameMachineResponse, error) | ||||||
| 	ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) | 	ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) | ||||||
|  | 	MoveMachine(ctx context.Context, in *MoveMachineRequest, opts ...grpc.CallOption) (*MoveMachineResponse, error) | ||||||
| 	// --- Route start --- | 	// --- Route start --- | ||||||
| 	GetMachineRoute(ctx context.Context, in *GetMachineRouteRequest, opts ...grpc.CallOption) (*GetMachineRouteResponse, error) | 	GetMachineRoute(ctx context.Context, in *GetMachineRouteRequest, opts ...grpc.CallOption) (*GetMachineRouteResponse, error) | ||||||
| 	EnableMachineRoutes(ctx context.Context, in *EnableMachineRoutesRequest, opts ...grpc.CallOption) (*EnableMachineRoutesResponse, error) | 	EnableMachineRoutes(ctx context.Context, in *EnableMachineRoutesRequest, opts ...grpc.CallOption) (*EnableMachineRoutesResponse, error) | ||||||
| @ -147,6 +145,15 @@ func (c *headscaleServiceClient) GetMachine(ctx context.Context, in *GetMachineR | |||||||
| 	return out, nil | 	return out, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *headscaleServiceClient) SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error) { | ||||||
|  | 	out := new(SetTagsResponse) | ||||||
|  | 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/SetTags", in, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *headscaleServiceClient) RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) { | func (c *headscaleServiceClient) RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) { | ||||||
| 	out := new(RegisterMachineResponse) | 	out := new(RegisterMachineResponse) | ||||||
| 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/RegisterMachine", in, out, opts...) | 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/RegisterMachine", in, out, opts...) | ||||||
| @ -192,6 +199,15 @@ func (c *headscaleServiceClient) ListMachines(ctx context.Context, in *ListMachi | |||||||
| 	return out, nil | 	return out, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *headscaleServiceClient) MoveMachine(ctx context.Context, in *MoveMachineRequest, opts ...grpc.CallOption) (*MoveMachineResponse, error) { | ||||||
|  | 	out := new(MoveMachineResponse) | ||||||
|  | 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/MoveMachine", in, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *headscaleServiceClient) GetMachineRoute(ctx context.Context, in *GetMachineRouteRequest, opts ...grpc.CallOption) (*GetMachineRouteResponse, error) { | func (c *headscaleServiceClient) GetMachineRoute(ctx context.Context, in *GetMachineRouteRequest, opts ...grpc.CallOption) (*GetMachineRouteResponse, error) { | ||||||
| 	out := new(GetMachineRouteResponse) | 	out := new(GetMachineRouteResponse) | ||||||
| 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetMachineRoute", in, out, opts...) | 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetMachineRoute", in, out, opts...) | ||||||
| @ -254,11 +270,13 @@ type HeadscaleServiceServer interface { | |||||||
| 	// --- Machine start --- | 	// --- Machine start --- | ||||||
| 	DebugCreateMachine(context.Context, *DebugCreateMachineRequest) (*DebugCreateMachineResponse, error) | 	DebugCreateMachine(context.Context, *DebugCreateMachineRequest) (*DebugCreateMachineResponse, error) | ||||||
| 	GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error) | 	GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error) | ||||||
|  | 	SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error) | ||||||
| 	RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error) | 	RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error) | ||||||
| 	DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error) | 	DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error) | ||||||
| 	ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error) | 	ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error) | ||||||
| 	RenameMachine(context.Context, *RenameMachineRequest) (*RenameMachineResponse, error) | 	RenameMachine(context.Context, *RenameMachineRequest) (*RenameMachineResponse, error) | ||||||
| 	ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) | 	ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) | ||||||
|  | 	MoveMachine(context.Context, *MoveMachineRequest) (*MoveMachineResponse, error) | ||||||
| 	// --- Route start --- | 	// --- Route start --- | ||||||
| 	GetMachineRoute(context.Context, *GetMachineRouteRequest) (*GetMachineRouteResponse, error) | 	GetMachineRoute(context.Context, *GetMachineRouteRequest) (*GetMachineRouteResponse, error) | ||||||
| 	EnableMachineRoutes(context.Context, *EnableMachineRoutesRequest) (*EnableMachineRoutesResponse, error) | 	EnableMachineRoutes(context.Context, *EnableMachineRoutesRequest) (*EnableMachineRoutesResponse, error) | ||||||
| @ -303,6 +321,9 @@ func (UnimplementedHeadscaleServiceServer) DebugCreateMachine(context.Context, * | |||||||
| func (UnimplementedHeadscaleServiceServer) GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error) { | func (UnimplementedHeadscaleServiceServer) GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error) { | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method GetMachine not implemented") | 	return nil, status.Errorf(codes.Unimplemented, "method GetMachine not implemented") | ||||||
| } | } | ||||||
|  | func (UnimplementedHeadscaleServiceServer) SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error) { | ||||||
|  | 	return nil, status.Errorf(codes.Unimplemented, "method SetTags not implemented") | ||||||
|  | } | ||||||
| func (UnimplementedHeadscaleServiceServer) RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error) { | func (UnimplementedHeadscaleServiceServer) RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error) { | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method RegisterMachine not implemented") | 	return nil, status.Errorf(codes.Unimplemented, "method RegisterMachine not implemented") | ||||||
| } | } | ||||||
| @ -318,6 +339,9 @@ func (UnimplementedHeadscaleServiceServer) RenameMachine(context.Context, *Renam | |||||||
| func (UnimplementedHeadscaleServiceServer) ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) { | func (UnimplementedHeadscaleServiceServer) ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) { | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method ListMachines not implemented") | 	return nil, status.Errorf(codes.Unimplemented, "method ListMachines not implemented") | ||||||
| } | } | ||||||
|  | func (UnimplementedHeadscaleServiceServer) MoveMachine(context.Context, *MoveMachineRequest) (*MoveMachineResponse, error) { | ||||||
|  | 	return nil, status.Errorf(codes.Unimplemented, "method MoveMachine not implemented") | ||||||
|  | } | ||||||
| func (UnimplementedHeadscaleServiceServer) GetMachineRoute(context.Context, *GetMachineRouteRequest) (*GetMachineRouteResponse, error) { | func (UnimplementedHeadscaleServiceServer) GetMachineRoute(context.Context, *GetMachineRouteRequest) (*GetMachineRouteResponse, error) { | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method GetMachineRoute not implemented") | 	return nil, status.Errorf(codes.Unimplemented, "method GetMachineRoute not implemented") | ||||||
| } | } | ||||||
| @ -526,6 +550,24 @@ func _HeadscaleService_GetMachine_Handler(srv interface{}, ctx context.Context, | |||||||
| 	return interceptor(ctx, in, info, handler) | 	return interceptor(ctx, in, info, handler) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func _HeadscaleService_SetTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||||
|  | 	in := new(SetTagsRequest) | ||||||
|  | 	if err := dec(in); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if interceptor == nil { | ||||||
|  | 		return srv.(HeadscaleServiceServer).SetTags(ctx, in) | ||||||
|  | 	} | ||||||
|  | 	info := &grpc.UnaryServerInfo{ | ||||||
|  | 		Server:     srv, | ||||||
|  | 		FullMethod: "/headscale.v1.HeadscaleService/SetTags", | ||||||
|  | 	} | ||||||
|  | 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||||||
|  | 		return srv.(HeadscaleServiceServer).SetTags(ctx, req.(*SetTagsRequest)) | ||||||
|  | 	} | ||||||
|  | 	return interceptor(ctx, in, info, handler) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func _HeadscaleService_RegisterMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | func _HeadscaleService_RegisterMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||||
| 	in := new(RegisterMachineRequest) | 	in := new(RegisterMachineRequest) | ||||||
| 	if err := dec(in); err != nil { | 	if err := dec(in); err != nil { | ||||||
| @ -616,6 +658,24 @@ func _HeadscaleService_ListMachines_Handler(srv interface{}, ctx context.Context | |||||||
| 	return interceptor(ctx, in, info, handler) | 	return interceptor(ctx, in, info, handler) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func _HeadscaleService_MoveMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||||
|  | 	in := new(MoveMachineRequest) | ||||||
|  | 	if err := dec(in); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if interceptor == nil { | ||||||
|  | 		return srv.(HeadscaleServiceServer).MoveMachine(ctx, in) | ||||||
|  | 	} | ||||||
|  | 	info := &grpc.UnaryServerInfo{ | ||||||
|  | 		Server:     srv, | ||||||
|  | 		FullMethod: "/headscale.v1.HeadscaleService/MoveMachine", | ||||||
|  | 	} | ||||||
|  | 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||||||
|  | 		return srv.(HeadscaleServiceServer).MoveMachine(ctx, req.(*MoveMachineRequest)) | ||||||
|  | 	} | ||||||
|  | 	return interceptor(ctx, in, info, handler) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func _HeadscaleService_GetMachineRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | func _HeadscaleService_GetMachineRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||||
| 	in := new(GetMachineRouteRequest) | 	in := new(GetMachineRouteRequest) | ||||||
| 	if err := dec(in); err != nil { | 	if err := dec(in); err != nil { | ||||||
| @ -753,6 +813,10 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{ | |||||||
| 			MethodName: "GetMachine", | 			MethodName: "GetMachine", | ||||||
| 			Handler:    _HeadscaleService_GetMachine_Handler, | 			Handler:    _HeadscaleService_GetMachine_Handler, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			MethodName: "SetTags", | ||||||
|  | 			Handler:    _HeadscaleService_SetTags_Handler, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			MethodName: "RegisterMachine", | 			MethodName: "RegisterMachine", | ||||||
| 			Handler:    _HeadscaleService_RegisterMachine_Handler, | 			Handler:    _HeadscaleService_RegisterMachine_Handler, | ||||||
| @ -773,6 +837,10 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{ | |||||||
| 			MethodName: "ListMachines", | 			MethodName: "ListMachines", | ||||||
| 			Handler:    _HeadscaleService_ListMachines_Handler, | 			Handler:    _HeadscaleService_ListMachines_Handler, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			MethodName: "MoveMachine", | ||||||
|  | 			Handler:    _HeadscaleService_MoveMachine_Handler, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			MethodName: "GetMachineRoute", | 			MethodName: "GetMachineRoute", | ||||||
| 			Handler:    _HeadscaleService_GetMachineRoute_Handler, | 			Handler:    _HeadscaleService_GetMachineRoute_Handler, | ||||||
|  | |||||||
| @ -91,7 +91,10 @@ type Machine struct { | |||||||
| 	PreAuthKey           *PreAuthKey            `protobuf:"bytes,11,opt,name=pre_auth_key,json=preAuthKey,proto3" json:"pre_auth_key,omitempty"` | 	PreAuthKey           *PreAuthKey            `protobuf:"bytes,11,opt,name=pre_auth_key,json=preAuthKey,proto3" json:"pre_auth_key,omitempty"` | ||||||
| 	CreatedAt            *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` | 	CreatedAt            *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` | ||||||
| 	RegisterMethod       RegisterMethod         `protobuf:"varint,13,opt,name=register_method,json=registerMethod,proto3,enum=headscale.v1.RegisterMethod" json:"register_method,omitempty"` | 	RegisterMethod       RegisterMethod         `protobuf:"varint,13,opt,name=register_method,json=registerMethod,proto3,enum=headscale.v1.RegisterMethod" json:"register_method,omitempty"` | ||||||
| 	GivenName            string                 `protobuf:"bytes,18,opt,name=given_name,json=givenName,proto3" json:"given_name,omitempty"` | 	ForcedTags           []string               `protobuf:"bytes,18,rep,name=forced_tags,json=forcedTags,proto3" json:"forced_tags,omitempty"` | ||||||
|  | 	InvalidTags          []string               `protobuf:"bytes,19,rep,name=invalid_tags,json=invalidTags,proto3" json:"invalid_tags,omitempty"` | ||||||
|  | 	ValidTags            []string               `protobuf:"bytes,20,rep,name=valid_tags,json=validTags,proto3" json:"valid_tags,omitempty"` | ||||||
|  | 	GivenName            string                 `protobuf:"bytes,21,opt,name=given_name,json=givenName,proto3" json:"given_name,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *Machine) Reset() { | func (x *Machine) Reset() { | ||||||
| @ -217,6 +220,27 @@ func (x *Machine) GetRegisterMethod() RegisterMethod { | |||||||
| 	return RegisterMethod_REGISTER_METHOD_UNSPECIFIED | 	return RegisterMethod_REGISTER_METHOD_UNSPECIFIED | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (x *Machine) GetForcedTags() []string { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.ForcedTags | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *Machine) GetInvalidTags() []string { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.InvalidTags | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *Machine) GetValidTags() []string { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.ValidTags | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (x *Machine) GetGivenName() string { | func (x *Machine) GetGivenName() string { | ||||||
| 	if x != nil { | 	if x != nil { | ||||||
| 		return x.GivenName | 		return x.GivenName | ||||||
| @ -420,6 +444,108 @@ func (x *GetMachineResponse) GetMachine() *Machine { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type SetTagsRequest struct { | ||||||
|  | 	state         protoimpl.MessageState | ||||||
|  | 	sizeCache     protoimpl.SizeCache | ||||||
|  | 	unknownFields protoimpl.UnknownFields | ||||||
|  | 
 | ||||||
|  | 	MachineId uint64   `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"` | ||||||
|  | 	Tags      []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsRequest) Reset() { | ||||||
|  | 	*x = SetTagsRequest{} | ||||||
|  | 	if protoimpl.UnsafeEnabled { | ||||||
|  | 		mi := &file_headscale_v1_machine_proto_msgTypes[5] | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		ms.StoreMessageInfo(mi) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsRequest) String() string { | ||||||
|  | 	return protoimpl.X.MessageStringOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (*SetTagsRequest) ProtoMessage() {} | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsRequest) ProtoReflect() protoreflect.Message { | ||||||
|  | 	mi := &file_headscale_v1_machine_proto_msgTypes[5] | ||||||
|  | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		if ms.LoadMessageInfo() == nil { | ||||||
|  | 			ms.StoreMessageInfo(mi) | ||||||
|  | 		} | ||||||
|  | 		return ms | ||||||
|  | 	} | ||||||
|  | 	return mi.MessageOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Deprecated: Use SetTagsRequest.ProtoReflect.Descriptor instead. | ||||||
|  | func (*SetTagsRequest) Descriptor() ([]byte, []int) { | ||||||
|  | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{5} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsRequest) GetMachineId() uint64 { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.MachineId | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsRequest) GetTags() []string { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.Tags | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type SetTagsResponse struct { | ||||||
|  | 	state         protoimpl.MessageState | ||||||
|  | 	sizeCache     protoimpl.SizeCache | ||||||
|  | 	unknownFields protoimpl.UnknownFields | ||||||
|  | 
 | ||||||
|  | 	Machine *Machine `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsResponse) Reset() { | ||||||
|  | 	*x = SetTagsResponse{} | ||||||
|  | 	if protoimpl.UnsafeEnabled { | ||||||
|  | 		mi := &file_headscale_v1_machine_proto_msgTypes[6] | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		ms.StoreMessageInfo(mi) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsResponse) String() string { | ||||||
|  | 	return protoimpl.X.MessageStringOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (*SetTagsResponse) ProtoMessage() {} | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsResponse) ProtoReflect() protoreflect.Message { | ||||||
|  | 	mi := &file_headscale_v1_machine_proto_msgTypes[6] | ||||||
|  | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		if ms.LoadMessageInfo() == nil { | ||||||
|  | 			ms.StoreMessageInfo(mi) | ||||||
|  | 		} | ||||||
|  | 		return ms | ||||||
|  | 	} | ||||||
|  | 	return mi.MessageOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Deprecated: Use SetTagsResponse.ProtoReflect.Descriptor instead. | ||||||
|  | func (*SetTagsResponse) Descriptor() ([]byte, []int) { | ||||||
|  | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{6} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *SetTagsResponse) GetMachine() *Machine { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.Machine | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type DeleteMachineRequest struct { | type DeleteMachineRequest struct { | ||||||
| 	state         protoimpl.MessageState | 	state         protoimpl.MessageState | ||||||
| 	sizeCache     protoimpl.SizeCache | 	sizeCache     protoimpl.SizeCache | ||||||
| @ -431,7 +557,7 @@ type DeleteMachineRequest struct { | |||||||
| func (x *DeleteMachineRequest) Reset() { | func (x *DeleteMachineRequest) Reset() { | ||||||
| 	*x = DeleteMachineRequest{} | 	*x = DeleteMachineRequest{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[5] | 		mi := &file_headscale_v1_machine_proto_msgTypes[7] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -444,7 +570,7 @@ func (x *DeleteMachineRequest) String() string { | |||||||
| func (*DeleteMachineRequest) ProtoMessage() {} | func (*DeleteMachineRequest) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *DeleteMachineRequest) ProtoReflect() protoreflect.Message { | func (x *DeleteMachineRequest) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[5] | 	mi := &file_headscale_v1_machine_proto_msgTypes[7] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -457,7 +583,7 @@ func (x *DeleteMachineRequest) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use DeleteMachineRequest.ProtoReflect.Descriptor instead. | // Deprecated: Use DeleteMachineRequest.ProtoReflect.Descriptor instead. | ||||||
| func (*DeleteMachineRequest) Descriptor() ([]byte, []int) { | func (*DeleteMachineRequest) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{5} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{7} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *DeleteMachineRequest) GetMachineId() uint64 { | func (x *DeleteMachineRequest) GetMachineId() uint64 { | ||||||
| @ -476,7 +602,7 @@ type DeleteMachineResponse struct { | |||||||
| func (x *DeleteMachineResponse) Reset() { | func (x *DeleteMachineResponse) Reset() { | ||||||
| 	*x = DeleteMachineResponse{} | 	*x = DeleteMachineResponse{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[6] | 		mi := &file_headscale_v1_machine_proto_msgTypes[8] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -489,7 +615,7 @@ func (x *DeleteMachineResponse) String() string { | |||||||
| func (*DeleteMachineResponse) ProtoMessage() {} | func (*DeleteMachineResponse) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *DeleteMachineResponse) ProtoReflect() protoreflect.Message { | func (x *DeleteMachineResponse) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[6] | 	mi := &file_headscale_v1_machine_proto_msgTypes[8] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -502,7 +628,7 @@ func (x *DeleteMachineResponse) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use DeleteMachineResponse.ProtoReflect.Descriptor instead. | // Deprecated: Use DeleteMachineResponse.ProtoReflect.Descriptor instead. | ||||||
| func (*DeleteMachineResponse) Descriptor() ([]byte, []int) { | func (*DeleteMachineResponse) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{6} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{8} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ExpireMachineRequest struct { | type ExpireMachineRequest struct { | ||||||
| @ -516,7 +642,7 @@ type ExpireMachineRequest struct { | |||||||
| func (x *ExpireMachineRequest) Reset() { | func (x *ExpireMachineRequest) Reset() { | ||||||
| 	*x = ExpireMachineRequest{} | 	*x = ExpireMachineRequest{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[7] | 		mi := &file_headscale_v1_machine_proto_msgTypes[9] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -529,7 +655,7 @@ func (x *ExpireMachineRequest) String() string { | |||||||
| func (*ExpireMachineRequest) ProtoMessage() {} | func (*ExpireMachineRequest) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *ExpireMachineRequest) ProtoReflect() protoreflect.Message { | func (x *ExpireMachineRequest) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[7] | 	mi := &file_headscale_v1_machine_proto_msgTypes[9] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -542,7 +668,7 @@ func (x *ExpireMachineRequest) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use ExpireMachineRequest.ProtoReflect.Descriptor instead. | // Deprecated: Use ExpireMachineRequest.ProtoReflect.Descriptor instead. | ||||||
| func (*ExpireMachineRequest) Descriptor() ([]byte, []int) { | func (*ExpireMachineRequest) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{7} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{9} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *ExpireMachineRequest) GetMachineId() uint64 { | func (x *ExpireMachineRequest) GetMachineId() uint64 { | ||||||
| @ -563,7 +689,7 @@ type ExpireMachineResponse struct { | |||||||
| func (x *ExpireMachineResponse) Reset() { | func (x *ExpireMachineResponse) Reset() { | ||||||
| 	*x = ExpireMachineResponse{} | 	*x = ExpireMachineResponse{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[8] | 		mi := &file_headscale_v1_machine_proto_msgTypes[10] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -576,7 +702,7 @@ func (x *ExpireMachineResponse) String() string { | |||||||
| func (*ExpireMachineResponse) ProtoMessage() {} | func (*ExpireMachineResponse) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *ExpireMachineResponse) ProtoReflect() protoreflect.Message { | func (x *ExpireMachineResponse) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[8] | 	mi := &file_headscale_v1_machine_proto_msgTypes[10] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -589,7 +715,7 @@ func (x *ExpireMachineResponse) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use ExpireMachineResponse.ProtoReflect.Descriptor instead. | // Deprecated: Use ExpireMachineResponse.ProtoReflect.Descriptor instead. | ||||||
| func (*ExpireMachineResponse) Descriptor() ([]byte, []int) { | func (*ExpireMachineResponse) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{8} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{10} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *ExpireMachineResponse) GetMachine() *Machine { | func (x *ExpireMachineResponse) GetMachine() *Machine { | ||||||
| @ -611,7 +737,7 @@ type RenameMachineRequest struct { | |||||||
| func (x *RenameMachineRequest) Reset() { | func (x *RenameMachineRequest) Reset() { | ||||||
| 	*x = RenameMachineRequest{} | 	*x = RenameMachineRequest{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[9] | 		mi := &file_headscale_v1_machine_proto_msgTypes[11] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -624,7 +750,7 @@ func (x *RenameMachineRequest) String() string { | |||||||
| func (*RenameMachineRequest) ProtoMessage() {} | func (*RenameMachineRequest) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *RenameMachineRequest) ProtoReflect() protoreflect.Message { | func (x *RenameMachineRequest) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[9] | 	mi := &file_headscale_v1_machine_proto_msgTypes[11] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -637,7 +763,7 @@ func (x *RenameMachineRequest) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use RenameMachineRequest.ProtoReflect.Descriptor instead. | // Deprecated: Use RenameMachineRequest.ProtoReflect.Descriptor instead. | ||||||
| func (*RenameMachineRequest) Descriptor() ([]byte, []int) { | func (*RenameMachineRequest) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{9} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{11} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *RenameMachineRequest) GetMachineId() uint64 { | func (x *RenameMachineRequest) GetMachineId() uint64 { | ||||||
| @ -665,7 +791,7 @@ type RenameMachineResponse struct { | |||||||
| func (x *RenameMachineResponse) Reset() { | func (x *RenameMachineResponse) Reset() { | ||||||
| 	*x = RenameMachineResponse{} | 	*x = RenameMachineResponse{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[10] | 		mi := &file_headscale_v1_machine_proto_msgTypes[12] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -678,7 +804,7 @@ func (x *RenameMachineResponse) String() string { | |||||||
| func (*RenameMachineResponse) ProtoMessage() {} | func (*RenameMachineResponse) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *RenameMachineResponse) ProtoReflect() protoreflect.Message { | func (x *RenameMachineResponse) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[10] | 	mi := &file_headscale_v1_machine_proto_msgTypes[12] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -691,7 +817,7 @@ func (x *RenameMachineResponse) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use RenameMachineResponse.ProtoReflect.Descriptor instead. | // Deprecated: Use RenameMachineResponse.ProtoReflect.Descriptor instead. | ||||||
| func (*RenameMachineResponse) Descriptor() ([]byte, []int) { | func (*RenameMachineResponse) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{10} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{12} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *RenameMachineResponse) GetMachine() *Machine { | func (x *RenameMachineResponse) GetMachine() *Machine { | ||||||
| @ -712,7 +838,7 @@ type ListMachinesRequest struct { | |||||||
| func (x *ListMachinesRequest) Reset() { | func (x *ListMachinesRequest) Reset() { | ||||||
| 	*x = ListMachinesRequest{} | 	*x = ListMachinesRequest{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[11] | 		mi := &file_headscale_v1_machine_proto_msgTypes[13] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -725,7 +851,7 @@ func (x *ListMachinesRequest) String() string { | |||||||
| func (*ListMachinesRequest) ProtoMessage() {} | func (*ListMachinesRequest) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { | func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[11] | 	mi := &file_headscale_v1_machine_proto_msgTypes[13] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -738,7 +864,7 @@ func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use ListMachinesRequest.ProtoReflect.Descriptor instead. | // Deprecated: Use ListMachinesRequest.ProtoReflect.Descriptor instead. | ||||||
| func (*ListMachinesRequest) Descriptor() ([]byte, []int) { | func (*ListMachinesRequest) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{11} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{13} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *ListMachinesRequest) GetNamespace() string { | func (x *ListMachinesRequest) GetNamespace() string { | ||||||
| @ -759,7 +885,7 @@ type ListMachinesResponse struct { | |||||||
| func (x *ListMachinesResponse) Reset() { | func (x *ListMachinesResponse) Reset() { | ||||||
| 	*x = ListMachinesResponse{} | 	*x = ListMachinesResponse{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[12] | 		mi := &file_headscale_v1_machine_proto_msgTypes[14] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -772,7 +898,7 @@ func (x *ListMachinesResponse) String() string { | |||||||
| func (*ListMachinesResponse) ProtoMessage() {} | func (*ListMachinesResponse) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { | func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[12] | 	mi := &file_headscale_v1_machine_proto_msgTypes[14] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -785,7 +911,7 @@ func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use ListMachinesResponse.ProtoReflect.Descriptor instead. | // Deprecated: Use ListMachinesResponse.ProtoReflect.Descriptor instead. | ||||||
| func (*ListMachinesResponse) Descriptor() ([]byte, []int) { | func (*ListMachinesResponse) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{12} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{14} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *ListMachinesResponse) GetMachines() []*Machine { | func (x *ListMachinesResponse) GetMachines() []*Machine { | ||||||
| @ -795,6 +921,108 @@ func (x *ListMachinesResponse) GetMachines() []*Machine { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type MoveMachineRequest struct { | ||||||
|  | 	state         protoimpl.MessageState | ||||||
|  | 	sizeCache     protoimpl.SizeCache | ||||||
|  | 	unknownFields protoimpl.UnknownFields | ||||||
|  | 
 | ||||||
|  | 	MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"` | ||||||
|  | 	Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineRequest) Reset() { | ||||||
|  | 	*x = MoveMachineRequest{} | ||||||
|  | 	if protoimpl.UnsafeEnabled { | ||||||
|  | 		mi := &file_headscale_v1_machine_proto_msgTypes[15] | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		ms.StoreMessageInfo(mi) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineRequest) String() string { | ||||||
|  | 	return protoimpl.X.MessageStringOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (*MoveMachineRequest) ProtoMessage() {} | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineRequest) ProtoReflect() protoreflect.Message { | ||||||
|  | 	mi := &file_headscale_v1_machine_proto_msgTypes[15] | ||||||
|  | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		if ms.LoadMessageInfo() == nil { | ||||||
|  | 			ms.StoreMessageInfo(mi) | ||||||
|  | 		} | ||||||
|  | 		return ms | ||||||
|  | 	} | ||||||
|  | 	return mi.MessageOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Deprecated: Use MoveMachineRequest.ProtoReflect.Descriptor instead. | ||||||
|  | func (*MoveMachineRequest) Descriptor() ([]byte, []int) { | ||||||
|  | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{15} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineRequest) GetMachineId() uint64 { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.MachineId | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineRequest) GetNamespace() string { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.Namespace | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type MoveMachineResponse struct { | ||||||
|  | 	state         protoimpl.MessageState | ||||||
|  | 	sizeCache     protoimpl.SizeCache | ||||||
|  | 	unknownFields protoimpl.UnknownFields | ||||||
|  | 
 | ||||||
|  | 	Machine *Machine `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineResponse) Reset() { | ||||||
|  | 	*x = MoveMachineResponse{} | ||||||
|  | 	if protoimpl.UnsafeEnabled { | ||||||
|  | 		mi := &file_headscale_v1_machine_proto_msgTypes[16] | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		ms.StoreMessageInfo(mi) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineResponse) String() string { | ||||||
|  | 	return protoimpl.X.MessageStringOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (*MoveMachineResponse) ProtoMessage() {} | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineResponse) ProtoReflect() protoreflect.Message { | ||||||
|  | 	mi := &file_headscale_v1_machine_proto_msgTypes[16] | ||||||
|  | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
|  | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
|  | 		if ms.LoadMessageInfo() == nil { | ||||||
|  | 			ms.StoreMessageInfo(mi) | ||||||
|  | 		} | ||||||
|  | 		return ms | ||||||
|  | 	} | ||||||
|  | 	return mi.MessageOf(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Deprecated: Use MoveMachineResponse.ProtoReflect.Descriptor instead. | ||||||
|  | func (*MoveMachineResponse) Descriptor() ([]byte, []int) { | ||||||
|  | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{16} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (x *MoveMachineResponse) GetMachine() *Machine { | ||||||
|  | 	if x != nil { | ||||||
|  | 		return x.Machine | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type DebugCreateMachineRequest struct { | type DebugCreateMachineRequest struct { | ||||||
| 	state         protoimpl.MessageState | 	state         protoimpl.MessageState | ||||||
| 	sizeCache     protoimpl.SizeCache | 	sizeCache     protoimpl.SizeCache | ||||||
| @ -809,7 +1037,7 @@ type DebugCreateMachineRequest struct { | |||||||
| func (x *DebugCreateMachineRequest) Reset() { | func (x *DebugCreateMachineRequest) Reset() { | ||||||
| 	*x = DebugCreateMachineRequest{} | 	*x = DebugCreateMachineRequest{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[13] | 		mi := &file_headscale_v1_machine_proto_msgTypes[17] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -822,7 +1050,7 @@ func (x *DebugCreateMachineRequest) String() string { | |||||||
| func (*DebugCreateMachineRequest) ProtoMessage() {} | func (*DebugCreateMachineRequest) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { | func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[13] | 	mi := &file_headscale_v1_machine_proto_msgTypes[17] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -835,7 +1063,7 @@ func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use DebugCreateMachineRequest.ProtoReflect.Descriptor instead. | // Deprecated: Use DebugCreateMachineRequest.ProtoReflect.Descriptor instead. | ||||||
| func (*DebugCreateMachineRequest) Descriptor() ([]byte, []int) { | func (*DebugCreateMachineRequest) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{13} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{17} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *DebugCreateMachineRequest) GetNamespace() string { | func (x *DebugCreateMachineRequest) GetNamespace() string { | ||||||
| @ -877,7 +1105,7 @@ type DebugCreateMachineResponse struct { | |||||||
| func (x *DebugCreateMachineResponse) Reset() { | func (x *DebugCreateMachineResponse) Reset() { | ||||||
| 	*x = DebugCreateMachineResponse{} | 	*x = DebugCreateMachineResponse{} | ||||||
| 	if protoimpl.UnsafeEnabled { | 	if protoimpl.UnsafeEnabled { | ||||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[14] | 		mi := &file_headscale_v1_machine_proto_msgTypes[18] | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		ms.StoreMessageInfo(mi) | 		ms.StoreMessageInfo(mi) | ||||||
| 	} | 	} | ||||||
| @ -890,7 +1118,7 @@ func (x *DebugCreateMachineResponse) String() string { | |||||||
| func (*DebugCreateMachineResponse) ProtoMessage() {} | func (*DebugCreateMachineResponse) ProtoMessage() {} | ||||||
| 
 | 
 | ||||||
| func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { | func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { | ||||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[14] | 	mi := &file_headscale_v1_machine_proto_msgTypes[18] | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { | 	if protoimpl.UnsafeEnabled && x != nil { | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||||
| 		if ms.LoadMessageInfo() == nil { | 		if ms.LoadMessageInfo() == nil { | ||||||
| @ -903,7 +1131,7 @@ func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { | |||||||
| 
 | 
 | ||||||
| // Deprecated: Use DebugCreateMachineResponse.ProtoReflect.Descriptor instead. | // Deprecated: Use DebugCreateMachineResponse.ProtoReflect.Descriptor instead. | ||||||
| func (*DebugCreateMachineResponse) Descriptor() ([]byte, []int) { | func (*DebugCreateMachineResponse) Descriptor() ([]byte, []int) { | ||||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{14} | 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{18} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (x *DebugCreateMachineResponse) GetMachine() *Machine { | func (x *DebugCreateMachineResponse) GetMachine() *Machine { | ||||||
| @ -924,7 +1152,7 @@ var file_headscale_v1_machine_proto_rawDesc = []byte{ | |||||||
| 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, | 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, | ||||||
| 	0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x68, 0x65, 0x61, 0x64, 0x73, | 	0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x68, 0x65, 0x61, 0x64, 0x73, | ||||||
| 	0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, | 	0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, | ||||||
| 	0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfc, 0x04, 0x0a, 0x07, 0x4d, 0x61, 0x63, | 	0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe5, 0x05, 0x0a, 0x07, 0x4d, 0x61, 0x63, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, | 	0x68, 0x69, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, | ||||||
| 	0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, | 	0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, | ||||||
| 	0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, | 	0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, | ||||||
| @ -962,81 +1190,106 @@ var file_headscale_v1_machine_proto_rawDesc = []byte{ | |||||||
| 	0x74, 0x68, 0x6f, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x68, 0x65, 0x61, | 	0x74, 0x68, 0x6f, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x68, 0x65, 0x61, | ||||||
| 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, | 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, | ||||||
| 	0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, | 	0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, | ||||||
| 	0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x76, 0x65, | 	0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x63, | ||||||
| 	0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, | 	0x65, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, | ||||||
| 	0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, | 	0x6f, 0x72, 0x63, 0x65, 0x64, 0x54, 0x61, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x76, | ||||||
| 	0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, | 	0x61, 0x6c, 0x69, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, | ||||||
| 	0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, | 	0x0b, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, | ||||||
| 	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, | 	0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, | ||||||
| 	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, | 	0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x67, | ||||||
| 	0x79, 0x22, 0x4a, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, | 	0x69, 0x76, 0x65, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, | 	0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x12, | ||||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, | 	0x22, 0x48, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, | ||||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, | 	0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x32, 0x0a, | 	0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, | ||||||
| 	0x11, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, | 	0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, | ||||||
|  | 	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4a, 0x0a, 0x17, 0x52, 0x65, | ||||||
|  | 	0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, | ||||||
|  | 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||||
|  | 	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||||
|  | 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, | ||||||
|  | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x32, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, | ||||||
|  | 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, | ||||||
|  | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, | ||||||
|  | 	0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x12, 0x47, 0x65, | ||||||
|  | 	0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, | ||||||
|  | 	0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||||
|  | 	0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, | ||||||
|  | 	0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
|  | 	0x65, 0x22, 0x43, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, | ||||||
|  | 	0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, | ||||||
|  | 	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||||
|  | 	0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, | ||||||
|  | 	0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0x42, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, | ||||||
|  | 	0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, | ||||||
|  | 	0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, | ||||||
|  | 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
|  | 	0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x35, 0x0a, 0x14, 0x44, 0x65, | ||||||
|  | 	0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, | ||||||
| 	0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, | 	0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, | ||||||
| 	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, | 	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, | ||||||
| 	0x64, 0x22, 0x45, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, | 	0x64, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, | 	0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x14, 0x45, 0x78, | ||||||
| 	0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, | 	0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, | ||||||
| 	0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, | 	0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, | ||||||
| 	0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x35, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, | 	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, | ||||||
| 	0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, | 	0x64, 0x22, 0x48, 0x0a, 0x15, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, | 	0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, | ||||||
| 	0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, | 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, | ||||||
| 	0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x69, | 	0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x50, 0x0a, 0x14, 0x52, | ||||||
| 	0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, | 	0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, | ||||||
| 	0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, | 	0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, | ||||||
| 	0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, | 	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||||
| 	0x48, 0x0a, 0x15, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | 	0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, | ||||||
| 	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, | 	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x48, 0x0a, | ||||||
| 	0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, | 	0x15, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, | ||||||
| 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | 	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x50, 0x0a, 0x14, 0x52, 0x65, 0x6e, | 	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, | ||||||
| 	0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, | 	0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, | ||||||
| 	0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, | 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, | ||||||
| 	0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, | ||||||
| 	0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, | 	0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||||
| 	0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x15, 0x52, | 	0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x14, | ||||||
| 	0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, | 	0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, | ||||||
| 	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, | 	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, | ||||||
| 	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | 	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||||
| 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, | 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, | ||||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x51, 0x0a, 0x12, 0x4d, 0x6f, 0x76, 0x65, 0x4d, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, | 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, | ||||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, | 	0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||||
| 	0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x14, 0x4c, 0x69, | 	0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, | ||||||
| 	0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, | 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, | ||||||
| 	0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, | 	0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x46, 0x0a, 0x13, 0x4d, 0x6f, | ||||||
| 	0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, | 	0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, | ||||||
| 	0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, | 	0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x77, 0x0a, 0x19, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, | 	0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, | ||||||
| 	0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, | 	0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, | ||||||
| 	0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, | 	0x6e, 0x65, 0x22, 0x77, 0x0a, 0x19, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, | ||||||
| 	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, | 	0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, | ||||||
| 	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, | 	0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, | ||||||
| 	0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, | 	0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, | ||||||
| 	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, | 	0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, | ||||||
| 	0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x4d, | 	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, | ||||||
| 	0x0a, 0x1a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, | 	0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, | 	0x03, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x1a, 0x44, | ||||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, | 	0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, | 	0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, | ||||||
| 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2a, 0x82, 0x01, | 	0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, | ||||||
| 	0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, | 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||||
| 	0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, | 	0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2a, 0x82, 0x01, 0x0a, 0x0e, 0x52, | ||||||
| 	0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, | 	0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, | ||||||
| 	0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, | 	0x1b, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, | ||||||
| 	0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, | 	0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, | ||||||
| 	0x17, 0x0a, 0x13, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, | 	0x0a, 0x18, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, | ||||||
| 	0x4f, 0x44, 0x5f, 0x43, 0x4c, 0x49, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x47, 0x49, | 	0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, | ||||||
| 	0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x49, 0x44, 0x43, | 	0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, | ||||||
| 	0x10, 0x03, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, | 	0x43, 0x4c, 0x49, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, | ||||||
| 	0x2f, 0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, | 	0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x49, 0x44, 0x43, 0x10, 0x03, 0x42, | ||||||
| 	0x61, 0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, | 	0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, | ||||||
| 	0x72, 0x6f, 0x74, 0x6f, 0x33, | 	0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, | ||||||
|  | 	0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, | ||||||
|  | 	0x6f, 0x33, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| @ -1052,7 +1305,7 @@ func file_headscale_v1_machine_proto_rawDescGZIP() []byte { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var file_headscale_v1_machine_proto_enumTypes = make([]protoimpl.EnumInfo, 1) | var file_headscale_v1_machine_proto_enumTypes = make([]protoimpl.EnumInfo, 1) | ||||||
| var file_headscale_v1_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 15) | var file_headscale_v1_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 19) | ||||||
| var file_headscale_v1_machine_proto_goTypes = []interface{}{ | var file_headscale_v1_machine_proto_goTypes = []interface{}{ | ||||||
| 	(RegisterMethod)(0),                // 0: headscale.v1.RegisterMethod | 	(RegisterMethod)(0),                // 0: headscale.v1.RegisterMethod | ||||||
| 	(*Machine)(nil),                    // 1: headscale.v1.Machine | 	(*Machine)(nil),                    // 1: headscale.v1.Machine | ||||||
| @ -1060,39 +1313,45 @@ var file_headscale_v1_machine_proto_goTypes = []interface{}{ | |||||||
| 	(*RegisterMachineResponse)(nil),    // 3: headscale.v1.RegisterMachineResponse | 	(*RegisterMachineResponse)(nil),    // 3: headscale.v1.RegisterMachineResponse | ||||||
| 	(*GetMachineRequest)(nil),          // 4: headscale.v1.GetMachineRequest | 	(*GetMachineRequest)(nil),          // 4: headscale.v1.GetMachineRequest | ||||||
| 	(*GetMachineResponse)(nil),         // 5: headscale.v1.GetMachineResponse | 	(*GetMachineResponse)(nil),         // 5: headscale.v1.GetMachineResponse | ||||||
| 	(*DeleteMachineRequest)(nil),       // 6: headscale.v1.DeleteMachineRequest | 	(*SetTagsRequest)(nil),             // 6: headscale.v1.SetTagsRequest | ||||||
| 	(*DeleteMachineResponse)(nil),      // 7: headscale.v1.DeleteMachineResponse | 	(*SetTagsResponse)(nil),            // 7: headscale.v1.SetTagsResponse | ||||||
| 	(*ExpireMachineRequest)(nil),       // 8: headscale.v1.ExpireMachineRequest | 	(*DeleteMachineRequest)(nil),       // 8: headscale.v1.DeleteMachineRequest | ||||||
| 	(*ExpireMachineResponse)(nil),      // 9: headscale.v1.ExpireMachineResponse | 	(*DeleteMachineResponse)(nil),      // 9: headscale.v1.DeleteMachineResponse | ||||||
| 	(*RenameMachineRequest)(nil),       // 10: headscale.v1.RenameMachineRequest | 	(*ExpireMachineRequest)(nil),       // 10: headscale.v1.ExpireMachineRequest | ||||||
| 	(*RenameMachineResponse)(nil),      // 11: headscale.v1.RenameMachineResponse | 	(*ExpireMachineResponse)(nil),      // 11: headscale.v1.ExpireMachineResponse | ||||||
| 	(*ListMachinesRequest)(nil),        // 12: headscale.v1.ListMachinesRequest | 	(*RenameMachineRequest)(nil),       // 12: headscale.v1.RenameMachineRequest | ||||||
| 	(*ListMachinesResponse)(nil),       // 13: headscale.v1.ListMachinesResponse | 	(*RenameMachineResponse)(nil),      // 13: headscale.v1.RenameMachineResponse | ||||||
| 	(*DebugCreateMachineRequest)(nil),  // 14: headscale.v1.DebugCreateMachineRequest | 	(*ListMachinesRequest)(nil),        // 14: headscale.v1.ListMachinesRequest | ||||||
| 	(*DebugCreateMachineResponse)(nil), // 15: headscale.v1.DebugCreateMachineResponse | 	(*ListMachinesResponse)(nil),       // 15: headscale.v1.ListMachinesResponse | ||||||
| 	(*Namespace)(nil),                  // 16: headscale.v1.Namespace | 	(*MoveMachineRequest)(nil),         // 16: headscale.v1.MoveMachineRequest | ||||||
| 	(*timestamppb.Timestamp)(nil),      // 17: google.protobuf.Timestamp | 	(*MoveMachineResponse)(nil),        // 17: headscale.v1.MoveMachineResponse | ||||||
| 	(*PreAuthKey)(nil),                 // 18: headscale.v1.PreAuthKey | 	(*DebugCreateMachineRequest)(nil),  // 18: headscale.v1.DebugCreateMachineRequest | ||||||
|  | 	(*DebugCreateMachineResponse)(nil), // 19: headscale.v1.DebugCreateMachineResponse | ||||||
|  | 	(*Namespace)(nil),                  // 20: headscale.v1.Namespace | ||||||
|  | 	(*timestamppb.Timestamp)(nil),      // 21: google.protobuf.Timestamp | ||||||
|  | 	(*PreAuthKey)(nil),                 // 22: headscale.v1.PreAuthKey | ||||||
| } | } | ||||||
| var file_headscale_v1_machine_proto_depIdxs = []int32{ | var file_headscale_v1_machine_proto_depIdxs = []int32{ | ||||||
| 	16, // 0: headscale.v1.Machine.namespace:type_name -> headscale.v1.Namespace | 	20, // 0: headscale.v1.Machine.namespace:type_name -> headscale.v1.Namespace | ||||||
| 	17, // 1: headscale.v1.Machine.last_seen:type_name -> google.protobuf.Timestamp | 	21, // 1: headscale.v1.Machine.last_seen:type_name -> google.protobuf.Timestamp | ||||||
| 	17, // 2: headscale.v1.Machine.last_successful_update:type_name -> google.protobuf.Timestamp | 	21, // 2: headscale.v1.Machine.last_successful_update:type_name -> google.protobuf.Timestamp | ||||||
| 	17, // 3: headscale.v1.Machine.expiry:type_name -> google.protobuf.Timestamp | 	21, // 3: headscale.v1.Machine.expiry:type_name -> google.protobuf.Timestamp | ||||||
| 	18, // 4: headscale.v1.Machine.pre_auth_key:type_name -> headscale.v1.PreAuthKey | 	22, // 4: headscale.v1.Machine.pre_auth_key:type_name -> headscale.v1.PreAuthKey | ||||||
| 	17, // 5: headscale.v1.Machine.created_at:type_name -> google.protobuf.Timestamp | 	21, // 5: headscale.v1.Machine.created_at:type_name -> google.protobuf.Timestamp | ||||||
| 	0,  // 6: headscale.v1.Machine.register_method:type_name -> headscale.v1.RegisterMethod | 	0,  // 6: headscale.v1.Machine.register_method:type_name -> headscale.v1.RegisterMethod | ||||||
| 	1,  // 7: headscale.v1.RegisterMachineResponse.machine:type_name -> headscale.v1.Machine | 	1,  // 7: headscale.v1.RegisterMachineResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	1,  // 8: headscale.v1.GetMachineResponse.machine:type_name -> headscale.v1.Machine | 	1,  // 8: headscale.v1.GetMachineResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	1,  // 9: headscale.v1.ExpireMachineResponse.machine:type_name -> headscale.v1.Machine | 	1,  // 9: headscale.v1.SetTagsResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	1,  // 10: headscale.v1.RenameMachineResponse.machine:type_name -> headscale.v1.Machine | 	1,  // 10: headscale.v1.ExpireMachineResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	1,  // 11: headscale.v1.ListMachinesResponse.machines:type_name -> headscale.v1.Machine | 	1,  // 11: headscale.v1.RenameMachineResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	1,  // 12: headscale.v1.DebugCreateMachineResponse.machine:type_name -> headscale.v1.Machine | 	1,  // 12: headscale.v1.ListMachinesResponse.machines:type_name -> headscale.v1.Machine | ||||||
| 	13, // [13:13] is the sub-list for method output_type | 	1,  // 13: headscale.v1.MoveMachineResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	13, // [13:13] is the sub-list for method input_type | 	1,  // 14: headscale.v1.DebugCreateMachineResponse.machine:type_name -> headscale.v1.Machine | ||||||
| 	13, // [13:13] is the sub-list for extension type_name | 	15, // [15:15] is the sub-list for method output_type | ||||||
| 	13, // [13:13] is the sub-list for extension extendee | 	15, // [15:15] is the sub-list for method input_type | ||||||
| 	0,  // [0:13] is the sub-list for field type_name | 	15, // [15:15] is the sub-list for extension type_name | ||||||
|  | 	15, // [15:15] is the sub-list for extension extendee | ||||||
|  | 	0,  // [0:15] is the sub-list for field type_name | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func init() { file_headscale_v1_machine_proto_init() } | func init() { file_headscale_v1_machine_proto_init() } | ||||||
| @ -1164,7 +1423,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*DeleteMachineRequest); i { | 			switch v := v.(*SetTagsRequest); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1176,7 +1435,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*DeleteMachineResponse); i { | 			switch v := v.(*SetTagsResponse); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1188,7 +1447,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*ExpireMachineRequest); i { | 			switch v := v.(*DeleteMachineRequest); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1200,7 +1459,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*ExpireMachineResponse); i { | 			switch v := v.(*DeleteMachineResponse); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1212,7 +1471,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*RenameMachineRequest); i { | 			switch v := v.(*ExpireMachineRequest); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1224,7 +1483,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*RenameMachineResponse); i { | 			switch v := v.(*ExpireMachineResponse); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1236,7 +1495,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*ListMachinesRequest); i { | 			switch v := v.(*RenameMachineRequest); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1248,7 +1507,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*ListMachinesResponse); i { | 			switch v := v.(*RenameMachineResponse); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1260,7 +1519,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*DebugCreateMachineRequest); i { | 			switch v := v.(*ListMachinesRequest); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| 			case 1: | 			case 1: | ||||||
| @ -1272,6 +1531,54 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		file_headscale_v1_machine_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { | 		file_headscale_v1_machine_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { | ||||||
|  | 			switch v := v.(*ListMachinesResponse); i { | ||||||
|  | 			case 0: | ||||||
|  | 				return &v.state | ||||||
|  | 			case 1: | ||||||
|  | 				return &v.sizeCache | ||||||
|  | 			case 2: | ||||||
|  | 				return &v.unknownFields | ||||||
|  | 			default: | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		file_headscale_v1_machine_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { | ||||||
|  | 			switch v := v.(*MoveMachineRequest); i { | ||||||
|  | 			case 0: | ||||||
|  | 				return &v.state | ||||||
|  | 			case 1: | ||||||
|  | 				return &v.sizeCache | ||||||
|  | 			case 2: | ||||||
|  | 				return &v.unknownFields | ||||||
|  | 			default: | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		file_headscale_v1_machine_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { | ||||||
|  | 			switch v := v.(*MoveMachineResponse); i { | ||||||
|  | 			case 0: | ||||||
|  | 				return &v.state | ||||||
|  | 			case 1: | ||||||
|  | 				return &v.sizeCache | ||||||
|  | 			case 2: | ||||||
|  | 				return &v.unknownFields | ||||||
|  | 			default: | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		file_headscale_v1_machine_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { | ||||||
|  | 			switch v := v.(*DebugCreateMachineRequest); i { | ||||||
|  | 			case 0: | ||||||
|  | 				return &v.state | ||||||
|  | 			case 1: | ||||||
|  | 				return &v.sizeCache | ||||||
|  | 			case 2: | ||||||
|  | 				return &v.unknownFields | ||||||
|  | 			default: | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		file_headscale_v1_machine_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { | ||||||
| 			switch v := v.(*DebugCreateMachineResponse); i { | 			switch v := v.(*DebugCreateMachineResponse); i { | ||||||
| 			case 0: | 			case 0: | ||||||
| 				return &v.state | 				return &v.state | ||||||
| @ -1290,7 +1597,7 @@ func file_headscale_v1_machine_proto_init() { | |||||||
| 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | ||||||
| 			RawDescriptor: file_headscale_v1_machine_proto_rawDesc, | 			RawDescriptor: file_headscale_v1_machine_proto_rawDesc, | ||||||
| 			NumEnums:      1, | 			NumEnums:      1, | ||||||
| 			NumMessages:   15, | 			NumMessages:   19, | ||||||
| 			NumExtensions: 0, | 			NumExtensions: 0, | ||||||
| 			NumServices:   0, | 			NumServices:   0, | ||||||
| 		}, | 		}, | ||||||
|  | |||||||
| @ -291,6 +291,43 @@ | |||||||
|         ] |         ] | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "/api/v1/machine/{machineId}/namespace": { | ||||||
|  |       "post": { | ||||||
|  |         "operationId": "HeadscaleService_MoveMachine", | ||||||
|  |         "responses": { | ||||||
|  |           "200": { | ||||||
|  |             "description": "A successful response.", | ||||||
|  |             "schema": { | ||||||
|  |               "$ref": "#/definitions/v1MoveMachineResponse" | ||||||
|  |             } | ||||||
|  |           }, | ||||||
|  |           "default": { | ||||||
|  |             "description": "An unexpected error response.", | ||||||
|  |             "schema": { | ||||||
|  |               "$ref": "#/definitions/rpcStatus" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "parameters": [ | ||||||
|  |           { | ||||||
|  |             "name": "machineId", | ||||||
|  |             "in": "path", | ||||||
|  |             "required": true, | ||||||
|  |             "type": "string", | ||||||
|  |             "format": "uint64" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "name": "namespace", | ||||||
|  |             "in": "query", | ||||||
|  |             "required": false, | ||||||
|  |             "type": "string" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "tags": [ | ||||||
|  |           "HeadscaleService" | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "/api/v1/machine/{machineId}/rename/{newName}": { |     "/api/v1/machine/{machineId}/rename/{newName}": { | ||||||
|       "post": { |       "post": { | ||||||
|         "operationId": "HeadscaleService_RenameMachine", |         "operationId": "HeadscaleService_RenameMachine", | ||||||
| @ -399,6 +436,53 @@ | |||||||
|         ] |         ] | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "/api/v1/machine/{machineId}/tags": { | ||||||
|  |       "post": { | ||||||
|  |         "operationId": "HeadscaleService_SetTags", | ||||||
|  |         "responses": { | ||||||
|  |           "200": { | ||||||
|  |             "description": "A successful response.", | ||||||
|  |             "schema": { | ||||||
|  |               "$ref": "#/definitions/v1SetTagsResponse" | ||||||
|  |             } | ||||||
|  |           }, | ||||||
|  |           "default": { | ||||||
|  |             "description": "An unexpected error response.", | ||||||
|  |             "schema": { | ||||||
|  |               "$ref": "#/definitions/rpcStatus" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "parameters": [ | ||||||
|  |           { | ||||||
|  |             "name": "machineId", | ||||||
|  |             "in": "path", | ||||||
|  |             "required": true, | ||||||
|  |             "type": "string", | ||||||
|  |             "format": "uint64" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "name": "body", | ||||||
|  |             "in": "body", | ||||||
|  |             "required": true, | ||||||
|  |             "schema": { | ||||||
|  |               "type": "object", | ||||||
|  |               "properties": { | ||||||
|  |                 "tags": { | ||||||
|  |                   "type": "array", | ||||||
|  |                   "items": { | ||||||
|  |                     "type": "string" | ||||||
|  |                   } | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "tags": [ | ||||||
|  |           "HeadscaleService" | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "/api/v1/namespace": { |     "/api/v1/namespace": { | ||||||
|       "get": { |       "get": { | ||||||
|         "operationId": "HeadscaleService_ListNamespaces", |         "operationId": "HeadscaleService_ListNamespaces", | ||||||
| @ -944,11 +1028,37 @@ | |||||||
|         "registerMethod": { |         "registerMethod": { | ||||||
|           "$ref": "#/definitions/v1RegisterMethod" |           "$ref": "#/definitions/v1RegisterMethod" | ||||||
|         }, |         }, | ||||||
|  |         "forcedTags": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "invalidTags": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "validTags": { | ||||||
|  |           "type": "array", | ||||||
|  |           "items": { | ||||||
|  |             "type": "string" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|         "givenName": { |         "givenName": { | ||||||
|           "type": "string" |           "type": "string" | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "v1MoveMachineResponse": { | ||||||
|  |       "type": "object", | ||||||
|  |       "properties": { | ||||||
|  |         "machine": { | ||||||
|  |           "$ref": "#/definitions/v1Machine" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "v1Namespace": { |     "v1Namespace": { | ||||||
|       "type": "object", |       "type": "object", | ||||||
|       "properties": { |       "properties": { | ||||||
| @ -1045,6 +1155,14 @@ | |||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     "v1SetTagsResponse": { | ||||||
|  |       "type": "object", | ||||||
|  |       "properties": { | ||||||
|  |         "machine": { | ||||||
|  |           "$ref": "#/definitions/v1Machine" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										97
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								go.mod
									
									
									
									
									
								
							| @ -3,76 +3,73 @@ module github.com/juanfont/headscale | |||||||
| go 1.18 | go 1.18 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/AlecAivazis/survey/v2 v2.3.2 | 	github.com/AlecAivazis/survey/v2 v2.3.4 | ||||||
| 	github.com/bufbuild/buf v1.4.0 |  | ||||||
| 	github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029 | 	github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029 | ||||||
| 	github.com/coreos/go-oidc/v3 v3.1.0 | 	github.com/coreos/go-oidc/v3 v3.1.0 | ||||||
| 	github.com/efekarakus/termcolor v1.0.1 | 	github.com/efekarakus/termcolor v1.0.1 | ||||||
| 	github.com/fatih/set v0.2.1 | 	github.com/fatih/set v0.2.1 | ||||||
| 	github.com/gin-gonic/gin v1.7.7 | 	github.com/gin-gonic/gin v1.7.7 | ||||||
| 	github.com/glebarez/sqlite v1.3.5 | 	github.com/glebarez/sqlite v1.4.3 | ||||||
| 	github.com/gofrs/uuid v4.2.0+incompatible | 	github.com/gofrs/uuid v4.2.0+incompatible | ||||||
| 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 | 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 | ||||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.3 | 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0 | ||||||
| 	github.com/infobloxopen/protoc-gen-gorm v1.1.0 |  | ||||||
| 	github.com/klauspost/compress v1.15.1 | 	github.com/klauspost/compress v1.15.1 | ||||||
| 	github.com/ory/dockertest/v3 v3.8.1 | 	github.com/ory/dockertest/v3 v3.8.1 | ||||||
| 	github.com/patrickmn/go-cache v2.1.0+incompatible | 	github.com/patrickmn/go-cache v2.1.0+incompatible | ||||||
| 	github.com/philip-bui/grpc-zerolog v1.0.1 | 	github.com/philip-bui/grpc-zerolog v1.0.1 | ||||||
| 	github.com/prometheus/client_golang v1.12.1 | 	github.com/prometheus/client_golang v1.12.1 | ||||||
| 	github.com/pterm/pterm v0.12.37 | 	github.com/pterm/pterm v0.12.41 | ||||||
| 	github.com/rs/zerolog v1.26.1 | 	github.com/rs/zerolog v1.26.1 | ||||||
| 	github.com/spf13/cobra v1.4.0 | 	github.com/spf13/cobra v1.4.0 | ||||||
| 	github.com/spf13/viper v1.10.1 | 	github.com/spf13/viper v1.11.0 | ||||||
| 	github.com/stretchr/testify v1.7.1 | 	github.com/stretchr/testify v1.7.1 | ||||||
| 	github.com/tailscale/hujson v0.0.0-20211215203138-ffd971c5f362 | 	github.com/tailscale/hujson v0.0.0-20220421170326-6583d0610064 | ||||||
| 	github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e | 	github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e | ||||||
| 	github.com/zsais/go-gin-prometheus v0.1.0 | 	github.com/zsais/go-gin-prometheus v0.1.0 | ||||||
| 	golang.org/x/crypto v0.0.0-20220214200702-86341886e292 | 	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 | ||||||
| 	golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b | 	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 | ||||||
| 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | ||||||
| 	google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4 | 	google.golang.org/genproto v0.0.0-20220422154200-b37d22cd5731 | ||||||
| 	google.golang.org/grpc v1.45.0 | 	google.golang.org/grpc v1.46.0 | ||||||
| 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0 |  | ||||||
| 	google.golang.org/protobuf v1.28.0 | 	google.golang.org/protobuf v1.28.0 | ||||||
| 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c | 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 | 	gopkg.in/yaml.v2 v2.4.0 | ||||||
| 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b | 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b | ||||||
| 	gorm.io/driver/postgres v1.3.1 | 	gorm.io/driver/postgres v1.3.5 | ||||||
| 	gorm.io/gorm v1.23.1 | 	gorm.io/gorm v1.23.4 | ||||||
| 	inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 | 	inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 | ||||||
| 	tailscale.com v1.22.0 | 	tailscale.com v1.24.0 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect | 	github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect | ||||||
| 	github.com/Microsoft/go-winio v0.5.2 // indirect | 	github.com/Microsoft/go-winio v0.5.1 // indirect | ||||||
| 	github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect | 	github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect | ||||||
| 	github.com/akutz/memconn v0.1.0 // indirect | 	github.com/akutz/memconn v0.1.0 // indirect | ||||||
|  | 	github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect | ||||||
| 	github.com/atomicgo/cursor v0.0.1 // indirect | 	github.com/atomicgo/cursor v0.0.1 // indirect | ||||||
| 	github.com/beorn7/perks v1.0.1 // indirect | 	github.com/beorn7/perks v1.0.1 // indirect | ||||||
|  | 	github.com/bufbuild/buf v1.4.0 // indirect | ||||||
| 	github.com/cenkalti/backoff/v4 v4.1.2 // indirect | 	github.com/cenkalti/backoff/v4 v4.1.2 // indirect | ||||||
| 	github.com/cespare/xxhash/v2 v2.1.2 // indirect | 	github.com/cespare/xxhash/v2 v2.1.2 // indirect | ||||||
| 	github.com/containerd/continuity v0.2.2 // indirect | 	github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 // indirect | ||||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect | 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect | ||||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||||
| 	github.com/denisenkom/go-mssqldb v0.12.0 // indirect | 	github.com/docker/cli v20.10.11+incompatible // indirect | ||||||
| 	github.com/docker/cli v20.10.12+incompatible // indirect | 	github.com/docker/docker v20.10.7+incompatible // indirect | ||||||
| 	github.com/docker/docker v20.10.12+incompatible // indirect |  | ||||||
| 	github.com/docker/go-connections v0.4.0 // indirect | 	github.com/docker/go-connections v0.4.0 // indirect | ||||||
| 	github.com/docker/go-units v0.4.0 // indirect | 	github.com/docker/go-units v0.4.0 // indirect | ||||||
| 	github.com/fsnotify/fsnotify v1.5.1 // indirect | 	github.com/fsnotify/fsnotify v1.5.1 // indirect | ||||||
| 	github.com/gin-contrib/sse v0.1.0 // indirect | 	github.com/gin-contrib/sse v0.1.0 // indirect | ||||||
| 	github.com/glebarez/go-sqlite v1.14.8 // indirect | 	github.com/glebarez/go-sqlite v1.16.0 // indirect | ||||||
| 	github.com/go-playground/locales v0.14.0 // indirect | 	github.com/go-playground/locales v0.13.0 // indirect | ||||||
| 	github.com/go-playground/universal-translator v0.18.0 // indirect | 	github.com/go-playground/universal-translator v0.17.0 // indirect | ||||||
| 	github.com/go-playground/validator/v10 v10.10.0 // indirect | 	github.com/go-playground/validator/v10 v10.4.1 // indirect | ||||||
| 	github.com/go-sql-driver/mysql v1.6.0 // indirect |  | ||||||
| 	github.com/gofrs/flock v0.8.1 // indirect | 	github.com/gofrs/flock v0.8.1 // indirect | ||||||
| 	github.com/gogo/protobuf v1.3.2 // indirect | 	github.com/gogo/protobuf v1.3.2 // indirect | ||||||
| 	github.com/golang/glog v1.0.0 // indirect |  | ||||||
| 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | ||||||
| 	github.com/golang/protobuf v1.5.2 // indirect | 	github.com/golang/protobuf v1.5.2 // indirect | ||||||
|  | 	github.com/google/go-cmp v0.5.7 // indirect | ||||||
| 	github.com/google/go-github v17.0.0+incompatible // indirect | 	github.com/google/go-github v17.0.0+incompatible // indirect | ||||||
| 	github.com/google/go-querystring v1.1.0 // indirect | 	github.com/google/go-querystring v1.1.0 // indirect | ||||||
| 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect | 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect | ||||||
| @ -83,42 +80,44 @@ require ( | |||||||
| 	github.com/imdario/mergo v0.3.12 // indirect | 	github.com/imdario/mergo v0.3.12 // indirect | ||||||
| 	github.com/inconshreveable/mousetrap v1.0.0 // indirect | 	github.com/inconshreveable/mousetrap v1.0.0 // indirect | ||||||
| 	github.com/jackc/chunkreader/v2 v2.0.1 // indirect | 	github.com/jackc/chunkreader/v2 v2.0.1 // indirect | ||||||
| 	github.com/jackc/pgconn v1.11.0 // indirect | 	github.com/jackc/pgconn v1.12.0 // indirect | ||||||
| 	github.com/jackc/pgio v1.0.0 // indirect | 	github.com/jackc/pgio v1.0.0 // indirect | ||||||
| 	github.com/jackc/pgpassfile v1.0.0 // indirect | 	github.com/jackc/pgpassfile v1.0.0 // indirect | ||||||
| 	github.com/jackc/pgproto3/v2 v2.2.0 // indirect | 	github.com/jackc/pgproto3/v2 v2.3.0 // indirect | ||||||
| 	github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect | 	github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect | ||||||
| 	github.com/jackc/pgtype v1.10.0 // indirect | 	github.com/jackc/pgtype v1.11.0 // indirect | ||||||
| 	github.com/jackc/pgx/v4 v4.15.0 // indirect | 	github.com/jackc/pgx/v4 v4.16.0 // indirect | ||||||
| 	github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect | 	github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect | ||||||
| 	github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f // indirect | 	github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f // indirect | ||||||
| 	github.com/jhump/protoreflect v1.12.1-0.20220417024638-438db461d753 // indirect | 	github.com/jhump/protoreflect v1.12.1-0.20220417024638-438db461d753 // indirect | ||||||
| 	github.com/jinzhu/gorm v1.9.16 // indirect |  | ||||||
| 	github.com/jinzhu/inflection v1.0.0 // indirect | 	github.com/jinzhu/inflection v1.0.0 // indirect | ||||||
| 	github.com/jinzhu/now v1.1.4 // indirect | 	github.com/jinzhu/now v1.1.4 // indirect | ||||||
|  | 	github.com/josharian/native v1.0.0 // indirect | ||||||
|  | 	github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b // indirect | ||||||
| 	github.com/json-iterator/go v1.1.12 // indirect | 	github.com/json-iterator/go v1.1.12 // indirect | ||||||
| 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | ||||||
| 	github.com/klauspost/pgzip v1.2.5 // indirect | 	github.com/klauspost/pgzip v1.2.5 // indirect | ||||||
| 	github.com/kr/pretty v0.3.0 // indirect | 	github.com/kr/pretty v0.3.0 // indirect | ||||||
| 	github.com/kr/text v0.2.0 // indirect | 	github.com/kr/text v0.2.0 // indirect | ||||||
| 	github.com/leodido/go-urn v1.2.1 // indirect | 	github.com/leodido/go-urn v1.2.0 // indirect | ||||||
| 	github.com/lib/pq v1.10.3 // indirect |  | ||||||
| 	github.com/magiconair/properties v1.8.6 // indirect | 	github.com/magiconair/properties v1.8.6 // indirect | ||||||
| 	github.com/mattn/go-colorable v0.1.12 // indirect | 	github.com/mattn/go-colorable v0.1.12 // indirect | ||||||
| 	github.com/mattn/go-isatty v0.0.14 // indirect | 	github.com/mattn/go-isatty v0.0.14 // indirect | ||||||
| 	github.com/mattn/go-runewidth v0.0.13 // indirect | 	github.com/mattn/go-runewidth v0.0.13 // indirect | ||||||
| 	github.com/mattn/go-sqlite3 v1.14.11 // indirect |  | ||||||
| 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect | 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect | ||||||
| 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect | 	github.com/mdlayher/netlink v1.6.0 // indirect | ||||||
|  | 	github.com/mdlayher/socket v0.2.3 // indirect | ||||||
|  | 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect | ||||||
| 	github.com/mitchellh/go-ps v1.0.0 // indirect | 	github.com/mitchellh/go-ps v1.0.0 // indirect | ||||||
| 	github.com/mitchellh/mapstructure v1.4.3 // indirect | 	github.com/mitchellh/mapstructure v1.4.3 // indirect | ||||||
| 	github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect | 	github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect | ||||||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||||
| 	github.com/modern-go/reflect2 v1.0.2 // indirect | 	github.com/modern-go/reflect2 v1.0.2 // indirect | ||||||
| 	github.com/opencontainers/go-digest v1.0.0 // indirect | 	github.com/opencontainers/go-digest v1.0.0-rc1 // indirect | ||||||
| 	github.com/opencontainers/image-spec v1.0.2 // indirect | 	github.com/opencontainers/image-spec v1.0.2 // indirect | ||||||
| 	github.com/opencontainers/runc v1.1.0 // indirect | 	github.com/opencontainers/runc v1.0.2 // indirect | ||||||
| 	github.com/pelletier/go-toml v1.9.4 // indirect | 	github.com/pelletier/go-toml v1.9.4 // indirect | ||||||
|  | 	github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect | ||||||
| 	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect | 	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect | ||||||
| 	github.com/pkg/errors v0.9.1 // indirect | 	github.com/pkg/errors v0.9.1 // indirect | ||||||
| 	github.com/pkg/profile v1.6.0 // indirect | 	github.com/pkg/profile v1.6.0 // indirect | ||||||
| @ -128,16 +127,16 @@ require ( | |||||||
| 	github.com/prometheus/procfs v0.7.3 // indirect | 	github.com/prometheus/procfs v0.7.3 // indirect | ||||||
| 	github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect | 	github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect | ||||||
| 	github.com/rivo/uniseg v0.2.0 // indirect | 	github.com/rivo/uniseg v0.2.0 // indirect | ||||||
| 	github.com/rogpeppe/go-internal v1.8.1 // indirect | 	github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 // indirect | ||||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||||||
| 	github.com/sirupsen/logrus v1.8.1 // indirect | 	github.com/sirupsen/logrus v1.8.1 // indirect | ||||||
| 	github.com/spf13/afero v1.8.1 // indirect | 	github.com/spf13/afero v1.8.2 // indirect | ||||||
| 	github.com/spf13/cast v1.4.1 // indirect | 	github.com/spf13/cast v1.4.1 // indirect | ||||||
| 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||||||
| 	github.com/spf13/pflag v1.0.5 // indirect | 	github.com/spf13/pflag v1.0.5 // indirect | ||||||
| 	github.com/subosito/gotenv v1.2.0 // indirect | 	github.com/subosito/gotenv v1.2.0 // indirect | ||||||
| 	github.com/ugorji/go/codec v1.2.7 // indirect | 	github.com/ugorji/go/codec v1.1.7 // indirect | ||||||
| 	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect | 	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect | ||||||
| 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect | 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect | ||||||
| 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect | 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect | ||||||
| 	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect | 	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect | ||||||
| @ -153,12 +152,12 @@ require ( | |||||||
| 	golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect | 	golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect | ||||||
| 	golang.org/x/text v0.3.7 // indirect | 	golang.org/x/text v0.3.7 // indirect | ||||||
| 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect | 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect | ||||||
|  | 	golang.zx2c4.com/wireguard/windows v0.4.10 // indirect | ||||||
| 	google.golang.org/appengine v1.6.7 // indirect | 	google.golang.org/appengine v1.6.7 // indirect | ||||||
| 	gopkg.in/ini.v1 v1.66.4 // indirect | 	gopkg.in/ini.v1 v1.66.4 // indirect | ||||||
| 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect | 	gopkg.in/square/go-jose.v2 v2.5.1 // indirect | ||||||
| 	modernc.org/libc v1.14.5 // indirect | 	modernc.org/libc v1.14.12 // indirect | ||||||
| 	modernc.org/mathutil v1.4.1 // indirect | 	modernc.org/mathutil v1.4.1 // indirect | ||||||
| 	modernc.org/memory v1.0.5 // indirect | 	modernc.org/memory v1.0.7 // indirect | ||||||
| 	modernc.org/sqlite v1.14.7 // indirect | 	modernc.org/sqlite v1.16.0 // indirect | ||||||
| 	sigs.k8s.io/yaml v1.3.0 // indirect |  | ||||||
| ) | ) | ||||||
|  | |||||||
							
								
								
									
										67
									
								
								grpcv1.go
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								grpcv1.go
									
									
									
									
									
								
							| @ -3,10 +3,13 @@ package headscale | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/juanfont/headscale/gen/go/headscale/v1" | 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
|  | 	"google.golang.org/grpc/codes" | ||||||
|  | 	"google.golang.org/grpc/status" | ||||||
| 	"tailscale.com/tailcfg" | 	"tailscale.com/tailcfg" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -182,6 +185,41 @@ func (api headscaleV1APIServer) GetMachine( | |||||||
| 	return &v1.GetMachineResponse{Machine: machine.toProto()}, nil | 	return &v1.GetMachineResponse{Machine: machine.toProto()}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (api headscaleV1APIServer) SetTags( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	request *v1.SetTagsRequest, | ||||||
|  | ) (*v1.SetTagsResponse, error) { | ||||||
|  | 	machine, err := api.h.GetMachineByID(request.GetMachineId()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, tag := range request.GetTags() { | ||||||
|  | 		if strings.Index(tag, "tag:") != 0 { | ||||||
|  | 			return &v1.SetTagsResponse{ | ||||||
|  | 					Machine: nil, | ||||||
|  | 				}, status.Error( | ||||||
|  | 					codes.InvalidArgument, | ||||||
|  | 					"Invalid tag detected. Each tag must start with the string 'tag:'", | ||||||
|  | 				) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = api.h.SetTags(machine, request.GetTags()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return &v1.SetTagsResponse{ | ||||||
|  | 			Machine: nil, | ||||||
|  | 		}, status.Error(codes.Internal, err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Trace(). | ||||||
|  | 		Str("machine", machine.Hostname). | ||||||
|  | 		Strs("tags", request.GetTags()). | ||||||
|  | 		Msg("Changing tags of machine") | ||||||
|  | 
 | ||||||
|  | 	return &v1.SetTagsResponse{Machine: machine.toProto()}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (api headscaleV1APIServer) DeleteMachine( | func (api headscaleV1APIServer) DeleteMachine( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	request *v1.DeleteMachineRequest, | 	request *v1.DeleteMachineRequest, | ||||||
| @ -272,12 +310,37 @@ func (api headscaleV1APIServer) ListMachines( | |||||||
| 
 | 
 | ||||||
| 	response := make([]*v1.Machine, len(machines)) | 	response := make([]*v1.Machine, len(machines)) | ||||||
| 	for index, machine := range machines { | 	for index, machine := range machines { | ||||||
| 		response[index] = machine.toProto() | 		m := machine.toProto() | ||||||
|  | 		validTags, invalidTags := getTags( | ||||||
|  | 			api.h.aclPolicy, | ||||||
|  | 			machine, | ||||||
|  | 			api.h.cfg.OIDC.StripEmaildomain, | ||||||
|  | 		) | ||||||
|  | 		m.InvalidTags = invalidTags | ||||||
|  | 		m.ValidTags = validTags | ||||||
|  | 		response[index] = m | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return &v1.ListMachinesResponse{Machines: response}, nil | 	return &v1.ListMachinesResponse{Machines: response}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (api headscaleV1APIServer) MoveMachine( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	request *v1.MoveMachineRequest, | ||||||
|  | ) (*v1.MoveMachineResponse, error) { | ||||||
|  | 	machine, err := api.h.GetMachineByID(request.GetMachineId()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = api.h.SetMachineNamespace(machine, request.GetNamespace()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &v1.MoveMachineResponse{Machine: machine.toProto()}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (api headscaleV1APIServer) GetMachineRoute( | func (api headscaleV1APIServer) GetMachineRoute( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	request *v1.GetMachineRouteRequest, | 	request *v1.GetMachineRouteRequest, | ||||||
|  | |||||||
| @ -525,6 +525,135 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() { | |||||||
| 	assert.Len(s.T(), listedPreAuthKeys, 2) | 	assert.Len(s.T(), listedPreAuthKeys, 2) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (s *IntegrationCLITestSuite) TestNodeTagCommand() { | ||||||
|  | 	namespace, err := s.createNamespace("machine-namespace") | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	machineKeys := []string{ | ||||||
|  | 		"9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
|  | 		"6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||||
|  | 	} | ||||||
|  | 	machines := make([]*v1.Machine, len(machineKeys)) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	for index, machineKey := range machineKeys { | ||||||
|  | 		_, err := ExecuteCommand( | ||||||
|  | 			&s.headscale, | ||||||
|  | 			[]string{ | ||||||
|  | 				"headscale", | ||||||
|  | 				"debug", | ||||||
|  | 				"create-node", | ||||||
|  | 				"--name", | ||||||
|  | 				fmt.Sprintf("machine-%d", index+1), | ||||||
|  | 				"--namespace", | ||||||
|  | 				namespace.Name, | ||||||
|  | 				"--key", | ||||||
|  | 				machineKey, | ||||||
|  | 				"--output", | ||||||
|  | 				"json", | ||||||
|  | 			}, | ||||||
|  | 			[]string{}, | ||||||
|  | 		) | ||||||
|  | 		assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 		machineResult, err := ExecuteCommand( | ||||||
|  | 			&s.headscale, | ||||||
|  | 			[]string{ | ||||||
|  | 				"headscale", | ||||||
|  | 				"nodes", | ||||||
|  | 				"--namespace", | ||||||
|  | 				namespace.Name, | ||||||
|  | 				"register", | ||||||
|  | 				"--key", | ||||||
|  | 				machineKey, | ||||||
|  | 				"--output", | ||||||
|  | 				"json", | ||||||
|  | 			}, | ||||||
|  | 			[]string{}, | ||||||
|  | 		) | ||||||
|  | 		assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 		var machine v1.Machine | ||||||
|  | 		err = json.Unmarshal([]byte(machineResult), &machine) | ||||||
|  | 		assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 		machines[index] = &machine | ||||||
|  | 	} | ||||||
|  | 	assert.Len(s.T(), machines, len(machineKeys)) | ||||||
|  | 
 | ||||||
|  | 	addTagResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"tag", | ||||||
|  | 			"-i", "1", | ||||||
|  | 			"-t", "tag:test", | ||||||
|  | 			"--output", "json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	var machine v1.Machine | ||||||
|  | 	err = json.Unmarshal([]byte(addTagResult), &machine) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 	assert.Equal(s.T(), []string{"tag:test"}, machine.ForcedTags) | ||||||
|  | 
 | ||||||
|  | 	// try to set a wrong tag and retrieve the error | ||||||
|  | 	wrongTagResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"tag", | ||||||
|  | 			"-i", "2", | ||||||
|  | 			"-t", "wrong-tag", | ||||||
|  | 			"--output", "json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 	type errOutput struct { | ||||||
|  | 		Error string `json:"error"` | ||||||
|  | 	} | ||||||
|  | 	var errorOutput errOutput | ||||||
|  | 	err = json.Unmarshal([]byte(wrongTagResult), &errorOutput) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 	assert.Contains(s.T(), errorOutput.Error, "Invalid tag detected") | ||||||
|  | 
 | ||||||
|  | 	// Test list all nodes after added seconds | ||||||
|  | 	listAllResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"list", | ||||||
|  | 			"--output", "json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	resultMachines := make([]*v1.Machine, len(machineKeys)) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 	json.Unmarshal([]byte(listAllResult), &resultMachines) | ||||||
|  | 	found := false | ||||||
|  | 	for _, machine := range resultMachines { | ||||||
|  | 		if machine.ForcedTags != nil { | ||||||
|  | 			for _, tag := range machine.ForcedTags { | ||||||
|  | 				if tag == "tag:test" { | ||||||
|  | 					found = true | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	assert.Equal( | ||||||
|  | 		s.T(), | ||||||
|  | 		true, | ||||||
|  | 		found, | ||||||
|  | 		"should find a machine with the tag 'tag:test' in the list of machines", | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (s *IntegrationCLITestSuite) TestNodeCommand() { | func (s *IntegrationCLITestSuite) TestNodeCommand() { | ||||||
| 	namespace, err := s.createNamespace("machine-namespace") | 	namespace, err := s.createNamespace("machine-namespace") | ||||||
| 	assert.Nil(s.T(), err) | 	assert.Nil(s.T(), err) | ||||||
| @ -1248,6 +1377,35 @@ func (s *IntegrationCLITestSuite) TestRouteCommand() { | |||||||
| 		string(failEnableNonAdvertisedRoute), | 		string(failEnableNonAdvertisedRoute), | ||||||
| 		"route (route-machine) is not available on node", | 		"route (route-machine) is not available on node", | ||||||
| 	) | 	) | ||||||
|  | 
 | ||||||
|  | 	// Enable all routes on host | ||||||
|  | 	enableAllRouteResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"routes", | ||||||
|  | 			"enable", | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 			"--identifier", | ||||||
|  | 			"0", | ||||||
|  | 			"--all", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	var enableAllRoute v1.Routes | ||||||
|  | 	err = json.Unmarshal([]byte(enableAllRouteResult), &enableAllRoute) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Len(s.T(), enableAllRoute.AdvertisedRoutes, 2) | ||||||
|  | 	assert.Contains(s.T(), enableAllRoute.AdvertisedRoutes, "10.0.0.0/8") | ||||||
|  | 	assert.Contains(s.T(), enableAllRoute.AdvertisedRoutes, "192.168.1.0/24") | ||||||
|  | 
 | ||||||
|  | 	assert.Len(s.T(), enableAllRoute.EnabledRoutes, 2) | ||||||
|  | 	assert.Contains(s.T(), enableAllRoute.EnabledRoutes, "10.0.0.0/8") | ||||||
|  | 	assert.Contains(s.T(), enableAllRoute.EnabledRoutes, "192.168.1.0/24") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *IntegrationCLITestSuite) TestApiKeyCommand() { | func (s *IntegrationCLITestSuite) TestApiKeyCommand() { | ||||||
| @ -1394,3 +1552,172 @@ func (s *IntegrationCLITestSuite) TestApiKeyCommand() { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (s *IntegrationCLITestSuite) TestNodeMoveCommand() { | ||||||
|  | 	oldNamespace, err := s.createNamespace("old-namespace") | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 	newNamespace, err := s.createNamespace("new-namespace") | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	// Randomly generated machine key | ||||||
|  | 	machineKey := "688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa" | ||||||
|  | 
 | ||||||
|  | 	_, err = ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"debug", | ||||||
|  | 			"create-node", | ||||||
|  | 			"--name", | ||||||
|  | 			"nomad-machine", | ||||||
|  | 			"--namespace", | ||||||
|  | 			oldNamespace.Name, | ||||||
|  | 			"--key", | ||||||
|  | 			machineKey, | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	machineResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"--namespace", | ||||||
|  | 			oldNamespace.Name, | ||||||
|  | 			"register", | ||||||
|  | 			"--key", | ||||||
|  | 			machineKey, | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	var machine v1.Machine | ||||||
|  | 	err = json.Unmarshal([]byte(machineResult), &machine) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(s.T(), uint64(1), machine.Id) | ||||||
|  | 	assert.Equal(s.T(), "nomad-machine", machine.Name) | ||||||
|  | 	assert.Equal(s.T(), machine.Namespace.Name, oldNamespace.Name) | ||||||
|  | 
 | ||||||
|  | 	machineId := fmt.Sprintf("%d", machine.Id) | ||||||
|  | 
 | ||||||
|  | 	moveToNewNSResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"move", | ||||||
|  | 			"--identifier", | ||||||
|  | 			machineId, | ||||||
|  | 			"--namespace", | ||||||
|  | 			newNamespace.Name, | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	err = json.Unmarshal([]byte(moveToNewNSResult), &machine) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(s.T(), machine.Namespace, newNamespace) | ||||||
|  | 
 | ||||||
|  | 	listAllNodesResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"list", | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	var allNodes []v1.Machine | ||||||
|  | 	err = json.Unmarshal([]byte(listAllNodesResult), &allNodes) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Len(s.T(), allNodes, 1) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(s.T(), allNodes[0].Id, machine.Id) | ||||||
|  | 	assert.Equal(s.T(), allNodes[0].Namespace, machine.Namespace) | ||||||
|  | 	assert.Equal(s.T(), allNodes[0].Namespace, newNamespace) | ||||||
|  | 
 | ||||||
|  | 	moveToNonExistingNSResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"move", | ||||||
|  | 			"--identifier", | ||||||
|  | 			machineId, | ||||||
|  | 			"--namespace", | ||||||
|  | 			"non-existing-namespace", | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Contains( | ||||||
|  | 		s.T(), | ||||||
|  | 		string(moveToNonExistingNSResult), | ||||||
|  | 		"Namespace not found", | ||||||
|  | 	) | ||||||
|  | 	assert.Equal(s.T(), machine.Namespace, newNamespace) | ||||||
|  | 
 | ||||||
|  | 	moveToOldNSResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"move", | ||||||
|  | 			"--identifier", | ||||||
|  | 			machineId, | ||||||
|  | 			"--namespace", | ||||||
|  | 			oldNamespace.Name, | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	err = json.Unmarshal([]byte(moveToOldNSResult), &machine) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(s.T(), machine.Namespace, oldNamespace) | ||||||
|  | 
 | ||||||
|  | 	moveToSameNSResult, err := ExecuteCommand( | ||||||
|  | 		&s.headscale, | ||||||
|  | 		[]string{ | ||||||
|  | 			"headscale", | ||||||
|  | 			"nodes", | ||||||
|  | 			"move", | ||||||
|  | 			"--identifier", | ||||||
|  | 			machineId, | ||||||
|  | 			"--namespace", | ||||||
|  | 			oldNamespace.Name, | ||||||
|  | 			"--output", | ||||||
|  | 			"json", | ||||||
|  | 		}, | ||||||
|  | 		[]string{}, | ||||||
|  | 	) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	err = json.Unmarshal([]byte(moveToSameNSResult), &machine) | ||||||
|  | 	assert.Nil(s.T(), err) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(s.T(), machine.Namespace, oldNamespace) | ||||||
|  | } | ||||||
|  | |||||||
| @ -20,7 +20,17 @@ var ( | |||||||
| 	IpPrefix4 = netaddr.MustParseIPPrefix("100.64.0.0/10") | 	IpPrefix4 = netaddr.MustParseIPPrefix("100.64.0.0/10") | ||||||
| 	IpPrefix6 = netaddr.MustParseIPPrefix("fd7a:115c:a1e0::/48") | 	IpPrefix6 = netaddr.MustParseIPPrefix("fd7a:115c:a1e0::/48") | ||||||
| 
 | 
 | ||||||
| 	tailscaleVersions = []string{"head", "unstable", "1.22.2", "1.20.4", "1.18.2", "1.16.2", "1.14.3", "1.12.3"} | 	tailscaleVersions = []string{ | ||||||
|  | 		"head", | ||||||
|  | 		"unstable", | ||||||
|  | 		"1.24.0", | ||||||
|  | 		"1.22.2", | ||||||
|  | 		"1.20.4", | ||||||
|  | 		"1.18.2", | ||||||
|  | 		"1.16.2", | ||||||
|  | 		"1.14.3", | ||||||
|  | 		"1.12.3", | ||||||
|  | 	} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type TestNamespace struct { | type TestNamespace struct { | ||||||
|  | |||||||
| @ -107,7 +107,10 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { | |||||||
| 	headscaleOptions := &dockertest.RunOptions{ | 	headscaleOptions := &dockertest.RunOptions{ | ||||||
| 		Name: headscaleHostname, | 		Name: headscaleHostname, | ||||||
| 		Mounts: []string{ | 		Mounts: []string{ | ||||||
| 			fmt.Sprintf("%s/integration_test/etc_embedded_derp:/etc/headscale", currentPath), | 			fmt.Sprintf( | ||||||
|  | 				"%s/integration_test/etc_embedded_derp:/etc/headscale", | ||||||
|  | 				currentPath, | ||||||
|  | 			), | ||||||
| 		}, | 		}, | ||||||
| 		Cmd:          []string{"headscale", "serve"}, | 		Cmd:          []string{"headscale", "serve"}, | ||||||
| 		ExposedPorts: []string{"8443/tcp", "3478/udp"}, | 		ExposedPorts: []string{"8443/tcp", "3478/udp"}, | ||||||
| @ -197,7 +200,10 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { | |||||||
| 	assert.Nil(s.T(), err) | 	assert.Nil(s.T(), err) | ||||||
| 	assert.True(s.T(), preAuthKey.Reusable) | 	assert.True(s.T(), preAuthKey.Reusable) | ||||||
| 
 | 
 | ||||||
| 	headscaleEndpoint := fmt.Sprintf("https://headscale:%s", s.headscale.GetPort("8443/tcp")) | 	headscaleEndpoint := fmt.Sprintf( | ||||||
|  | 		"https://headscale:%s", | ||||||
|  | 		s.headscale.GetPort("8443/tcp"), | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	log.Printf( | 	log.Printf( | ||||||
| 		"Joining tailscale containers to headscale at %s\n", | 		"Joining tailscale containers to headscale at %s\n", | ||||||
| @ -243,7 +249,9 @@ func (s *IntegrationDERPTestSuite) Join( | |||||||
| 	log.Printf("%s joined\n", hostname) | 	log.Printf("%s joined\n", hostname) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *IntegrationDERPTestSuite) tailscaleContainer(identifier, version string, network dockertest.Network, | func (s *IntegrationDERPTestSuite) tailscaleContainer( | ||||||
|  | 	identifier, version string, | ||||||
|  | 	network dockertest.Network, | ||||||
| ) (string, *dockertest.Resource) { | ) (string, *dockertest.Resource) { | ||||||
| 	tailscaleBuildOptions := getDockerBuildOptions(version) | 	tailscaleBuildOptions := getDockerBuildOptions(version) | ||||||
| 
 | 
 | ||||||
| @ -260,7 +268,10 @@ func (s *IntegrationDERPTestSuite) tailscaleContainer(identifier, version string | |||||||
| 		}, | 		}, | ||||||
| 
 | 
 | ||||||
| 		// expose the host IP address, so we can access it from inside the container | 		// expose the host IP address, so we can access it from inside the container | ||||||
| 		ExtraHosts: []string{"host.docker.internal:host-gateway", "headscale:host-gateway"}, | 		ExtraHosts: []string{ | ||||||
|  | 			"host.docker.internal:host-gateway", | ||||||
|  | 			"headscale:host-gateway", | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pts, err := s.pool.BuildAndRunWithBuildOptions( | 	pts, err := s.pool.BuildAndRunWithBuildOptions( | ||||||
|  | |||||||
| @ -47,11 +47,11 @@ func TestIntegrationTestSuite(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	s.namespaces = map[string]TestNamespace{ | 	s.namespaces = map[string]TestNamespace{ | ||||||
| 		"thisspace": { | 		"thisspace": { | ||||||
| 			count:      15, | 			count:      10, | ||||||
| 			tailscales: make(map[string]dockertest.Resource), | 			tailscales: make(map[string]dockertest.Resource), | ||||||
| 		}, | 		}, | ||||||
| 		"otherspace": { | 		"otherspace": { | ||||||
| 			count:      5, | 			count:      2, | ||||||
| 			tailscales: make(map[string]dockertest.Resource), | 			tailscales: make(map[string]dockertest.Resource), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										64
									
								
								machine.go
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								machine.go
									
									
									
									
									
								
							| @ -2,6 +2,7 @@ package headscale | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"database/sql/driver" | 	"database/sql/driver" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @ -57,6 +58,8 @@ type Machine struct { | |||||||
| 
 | 
 | ||||||
| 	RegisterMethod string | 	RegisterMethod string | ||||||
| 
 | 
 | ||||||
|  | 	ForcedTags StringList | ||||||
|  | 
 | ||||||
| 	// TODO(kradalby): This seems like irrelevant information? | 	// TODO(kradalby): This seems like irrelevant information? | ||||||
| 	AuthKeyID uint | 	AuthKeyID uint | ||||||
| 	AuthKey   *PreAuthKey | 	AuthKey   *PreAuthKey | ||||||
| @ -134,7 +137,7 @@ func (machine Machine) isExpired() bool { | |||||||
| 
 | 
 | ||||||
| func containsAddresses(inputs []string, addrs []string) bool { | func containsAddresses(inputs []string, addrs []string) bool { | ||||||
| 	for _, addr := range addrs { | 	for _, addr := range addrs { | ||||||
| 		if containsString(inputs, addr) { | 		if contains(inputs, addr) { | ||||||
| 			return true | 			return true | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -369,6 +372,18 @@ func (h *Headscale) UpdateMachine(machine *Machine) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // SetTags takes a Machine struct pointer and update the forced tags. | ||||||
|  | func (h *Headscale) SetTags(machine *Machine, tags []string) error { | ||||||
|  | 	machine.ForcedTags = tags | ||||||
|  | 	if err := h.UpdateACLRules(); err != nil && !errors.Is(err, errEmptyPolicy) { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	h.setLastStateChangeToNow(machine.Namespace.Name) | ||||||
|  | 	h.db.Save(machine) | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // ExpireMachine takes a Machine struct and sets the expire field to now. | // ExpireMachine takes a Machine struct and sets the expire field to now. | ||||||
| func (h *Headscale) ExpireMachine(machine *Machine) { | func (h *Headscale) ExpireMachine(machine *Machine) { | ||||||
| 	now := time.Now() | 	now := time.Now() | ||||||
| @ -651,6 +666,7 @@ func (machine *Machine) toProto() *v1.Machine { | |||||||
| 		Name:        machine.Hostname, | 		Name:        machine.Hostname, | ||||||
| 		GivenName:   machine.GivenName, | 		GivenName:   machine.GivenName, | ||||||
| 		Namespace:   machine.Namespace.toProto(), | 		Namespace:   machine.Namespace.toProto(), | ||||||
|  | 		ForcedTags:  machine.ForcedTags, | ||||||
| 
 | 
 | ||||||
| 		// TODO(kradalby): Implement register method enum converter | 		// TODO(kradalby): Implement register method enum converter | ||||||
| 		// RegisterMethod: , | 		// RegisterMethod: , | ||||||
| @ -679,6 +695,50 @@ func (machine *Machine) toProto() *v1.Machine { | |||||||
| 	return machineProto | 	return machineProto | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // getTags will return the tags of the current machine. | ||||||
|  | // Invalid tags are tags added by a user on a node, and that user doesn't have authority to add this tag. | ||||||
|  | // Valid tags are tags added by a user that is allowed in the ACL policy to add this tag. | ||||||
|  | func getTags( | ||||||
|  | 	aclPolicy *ACLPolicy, | ||||||
|  | 	machine Machine, | ||||||
|  | 	stripEmailDomain bool, | ||||||
|  | ) ([]string, []string) { | ||||||
|  | 	validTags := make([]string, 0) | ||||||
|  | 	invalidTags := make([]string, 0) | ||||||
|  | 	if aclPolicy == nil { | ||||||
|  | 		return validTags, invalidTags | ||||||
|  | 	} | ||||||
|  | 	validTagMap := make(map[string]bool) | ||||||
|  | 	invalidTagMap := make(map[string]bool) | ||||||
|  | 	for _, tag := range machine.HostInfo.RequestTags { | ||||||
|  | 		owners, err := expandTagOwners(*aclPolicy, tag, stripEmailDomain) | ||||||
|  | 		if errors.Is(err, errInvalidTag) { | ||||||
|  | 			invalidTagMap[tag] = true | ||||||
|  | 
 | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		var found bool | ||||||
|  | 		for _, owner := range owners { | ||||||
|  | 			if machine.Namespace.Name == owner { | ||||||
|  | 				found = true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if found { | ||||||
|  | 			validTagMap[tag] = true | ||||||
|  | 		} else { | ||||||
|  | 			invalidTagMap[tag] = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for tag := range invalidTagMap { | ||||||
|  | 		invalidTags = append(invalidTags, tag) | ||||||
|  | 	} | ||||||
|  | 	for tag := range validTagMap { | ||||||
|  | 		validTags = append(validTags, tag) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return validTags, invalidTags | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (h *Headscale) RegisterMachineFromAuthCallback( | func (h *Headscale) RegisterMachineFromAuthCallback( | ||||||
| 	machineKeyStr string, | 	machineKeyStr string, | ||||||
| 	namespaceName string, | 	namespaceName string, | ||||||
| @ -789,7 +849,7 @@ func (h *Headscale) EnableRoutes(machine *Machine, routeStrs ...string) error { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, newRoute := range newRoutes { | 	for _, newRoute := range newRoutes { | ||||||
| 		if !containsIPPrefix(machine.GetAdvertisedRoutes(), newRoute) { | 		if !contains(machine.GetAdvertisedRoutes(), newRoute) { | ||||||
| 			return fmt.Errorf( | 			return fmt.Errorf( | ||||||
| 				"route (%s) is not available on node %s: %w", | 				"route (%s) is not available on node %s: %w", | ||||||
| 				machine.Hostname, | 				machine.Hostname, | ||||||
|  | |||||||
							
								
								
									
										151
									
								
								machine_test.go
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								machine_test.go
									
									
									
									
									
								
							| @ -278,6 +278,157 @@ func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func Test_getTags(t *testing.T) { | ||||||
|  | 	type args struct { | ||||||
|  | 		aclPolicy        *ACLPolicy | ||||||
|  | 		machine          Machine | ||||||
|  | 		stripEmailDomain bool | ||||||
|  | 	} | ||||||
|  | 	tests := []struct { | ||||||
|  | 		name        string | ||||||
|  | 		args        args | ||||||
|  | 		wantInvalid []string | ||||||
|  | 		wantValid   []string | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			name: "valid tag one machine", | ||||||
|  | 			args: args{ | ||||||
|  | 				aclPolicy: &ACLPolicy{ | ||||||
|  | 					TagOwners: TagOwners{ | ||||||
|  | 						"tag:valid": []string{"joe"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				machine: Machine{ | ||||||
|  | 					Namespace: Namespace{ | ||||||
|  | 						Name: "joe", | ||||||
|  | 					}, | ||||||
|  | 					HostInfo: HostInfo{ | ||||||
|  | 						RequestTags: []string{"tag:valid"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				stripEmailDomain: false, | ||||||
|  | 			}, | ||||||
|  | 			wantValid:   []string{"tag:valid"}, | ||||||
|  | 			wantInvalid: nil, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "invalid tag and valid tag one machine", | ||||||
|  | 			args: args{ | ||||||
|  | 				aclPolicy: &ACLPolicy{ | ||||||
|  | 					TagOwners: TagOwners{ | ||||||
|  | 						"tag:valid": []string{"joe"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				machine: Machine{ | ||||||
|  | 					Namespace: Namespace{ | ||||||
|  | 						Name: "joe", | ||||||
|  | 					}, | ||||||
|  | 					HostInfo: HostInfo{ | ||||||
|  | 						RequestTags: []string{"tag:valid", "tag:invalid"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				stripEmailDomain: false, | ||||||
|  | 			}, | ||||||
|  | 			wantValid:   []string{"tag:valid"}, | ||||||
|  | 			wantInvalid: []string{"tag:invalid"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "multiple invalid and identical tags, should return only one invalid tag", | ||||||
|  | 			args: args{ | ||||||
|  | 				aclPolicy: &ACLPolicy{ | ||||||
|  | 					TagOwners: TagOwners{ | ||||||
|  | 						"tag:valid": []string{"joe"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				machine: Machine{ | ||||||
|  | 					Namespace: Namespace{ | ||||||
|  | 						Name: "joe", | ||||||
|  | 					}, | ||||||
|  | 					HostInfo: HostInfo{ | ||||||
|  | 						RequestTags: []string{ | ||||||
|  | 							"tag:invalid", | ||||||
|  | 							"tag:valid", | ||||||
|  | 							"tag:invalid", | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				stripEmailDomain: false, | ||||||
|  | 			}, | ||||||
|  | 			wantValid:   []string{"tag:valid"}, | ||||||
|  | 			wantInvalid: []string{"tag:invalid"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "only invalid tags", | ||||||
|  | 			args: args{ | ||||||
|  | 				aclPolicy: &ACLPolicy{ | ||||||
|  | 					TagOwners: TagOwners{ | ||||||
|  | 						"tag:valid": []string{"joe"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				machine: Machine{ | ||||||
|  | 					Namespace: Namespace{ | ||||||
|  | 						Name: "joe", | ||||||
|  | 					}, | ||||||
|  | 					HostInfo: HostInfo{ | ||||||
|  | 						RequestTags: []string{"tag:invalid", "very-invalid"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				stripEmailDomain: false, | ||||||
|  | 			}, | ||||||
|  | 			wantValid:   nil, | ||||||
|  | 			wantInvalid: []string{"tag:invalid", "very-invalid"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "empty ACLPolicy should return empty tags and should not panic", | ||||||
|  | 			args: args{ | ||||||
|  | 				aclPolicy: nil, | ||||||
|  | 				machine: Machine{ | ||||||
|  | 					Namespace: Namespace{ | ||||||
|  | 						Name: "joe", | ||||||
|  | 					}, | ||||||
|  | 					HostInfo: HostInfo{ | ||||||
|  | 						RequestTags: []string{"tag:invalid", "very-invalid"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				stripEmailDomain: false, | ||||||
|  | 			}, | ||||||
|  | 			wantValid:   nil, | ||||||
|  | 			wantInvalid: nil, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	for _, test := range tests { | ||||||
|  | 		t.Run(test.name, func(t *testing.T) { | ||||||
|  | 			gotValid, gotInvalid := getTags( | ||||||
|  | 				test.args.aclPolicy, | ||||||
|  | 				test.args.machine, | ||||||
|  | 				test.args.stripEmailDomain, | ||||||
|  | 			) | ||||||
|  | 			for _, valid := range gotValid { | ||||||
|  | 				if !contains(test.wantValid, valid) { | ||||||
|  | 					t.Errorf( | ||||||
|  | 						"valids: getTags() = %v, want %v", | ||||||
|  | 						gotValid, | ||||||
|  | 						test.wantValid, | ||||||
|  | 					) | ||||||
|  | 
 | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			for _, invalid := range gotInvalid { | ||||||
|  | 				if !contains(test.wantInvalid, invalid) { | ||||||
|  | 					t.Errorf( | ||||||
|  | 						"invalids: getTags() = %v, want %v", | ||||||
|  | 						gotInvalid, | ||||||
|  | 						test.wantInvalid, | ||||||
|  | 					) | ||||||
|  | 
 | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // nolint | // nolint | ||||||
| func Test_getFilteredByACLPeers(t *testing.T) { | func Test_getFilteredByACLPeers(t *testing.T) { | ||||||
| 	type args struct { | 	type args struct { | ||||||
|  | |||||||
| @ -177,8 +177,10 @@ func (h *Headscale) SetMachineNamespace(machine *Machine, namespaceName string) | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	machine.NamespaceID = namespace.ID | 	machine.Namespace = *namespace | ||||||
| 	h.db.Save(&machine) | 	if result := h.db.Save(&machine); result.Error != nil { | ||||||
|  | 		return result.Error | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -372,3 +372,40 @@ func TestCheckForFQDNRules(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) TestSetMachineNamespace(c *check.C) { | ||||||
|  | 	oldNamespace, err := app.CreateNamespace("old") | ||||||
|  | 	c.Assert(err, check.IsNil) | ||||||
|  | 
 | ||||||
|  | 	newNamespace, err := app.CreateNamespace("new") | ||||||
|  | 	c.Assert(err, check.IsNil) | ||||||
|  | 
 | ||||||
|  | 	pak, err := app.CreatePreAuthKey(oldNamespace.Name, false, false, nil) | ||||||
|  | 	c.Assert(err, check.IsNil) | ||||||
|  | 
 | ||||||
|  | 	machine := Machine{ | ||||||
|  | 		ID:             0, | ||||||
|  | 		MachineKey:     "foo", | ||||||
|  | 		NodeKey:        "bar", | ||||||
|  | 		DiscoKey:       "faa", | ||||||
|  | 		Hostname:       "testmachine", | ||||||
|  | 		NamespaceID:    oldNamespace.ID, | ||||||
|  | 		RegisterMethod: RegisterMethodAuthKey, | ||||||
|  | 		AuthKeyID:      uint(pak.ID), | ||||||
|  | 	} | ||||||
|  | 	app.db.Save(&machine) | ||||||
|  | 	c.Assert(machine.NamespaceID, check.Equals, oldNamespace.ID) | ||||||
|  | 
 | ||||||
|  | 	err = app.SetMachineNamespace(&machine, newNamespace.Name) | ||||||
|  | 	c.Assert(err, check.IsNil) | ||||||
|  | 	c.Assert(machine.NamespaceID, check.Equals, newNamespace.ID) | ||||||
|  | 	c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name) | ||||||
|  | 
 | ||||||
|  | 	err = app.SetMachineNamespace(&machine, "non-existing-namespace") | ||||||
|  | 	c.Assert(err, check.Equals, errNamespaceNotFound) | ||||||
|  | 
 | ||||||
|  | 	err = app.SetMachineNamespace(&machine, newNamespace.Name) | ||||||
|  | 	c.Assert(err, check.IsNil) | ||||||
|  | 	c.Assert(machine.NamespaceID, check.Equals, newNamespace.ID) | ||||||
|  | 	c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name) | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										34
									
								
								oidc.go
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								oidc.go
									
									
									
									
									
								
							| @ -53,7 +53,7 @@ func (h *Headscale) initOIDC() error { | |||||||
| 				"%s/oidc/callback", | 				"%s/oidc/callback", | ||||||
| 				strings.TrimSuffix(h.cfg.ServerURL, "/"), | 				strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||||
| 			), | 			), | ||||||
| 			Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, | 			Scopes: h.cfg.OIDC.Scope, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -91,7 +91,14 @@ func (h *Headscale) RegisterOIDC(ctx *gin.Context) { | |||||||
| 	// place the machine key into the state cache, so it can be retrieved later | 	// place the machine key into the state cache, so it can be retrieved later | ||||||
| 	h.registrationCache.Set(stateStr, machineKeyStr, registerCacheExpiration) | 	h.registrationCache.Set(stateStr, machineKeyStr, registerCacheExpiration) | ||||||
| 
 | 
 | ||||||
| 	authURL := h.oauth2Config.AuthCodeURL(stateStr) | 	// Add any extra parameter provided in the configuration to the Authorize Endpoint request | ||||||
|  | 	extras := make([]oauth2.AuthCodeOption, 0, len(h.cfg.OIDC.ExtraParams)) | ||||||
|  | 
 | ||||||
|  | 	for k, v := range h.cfg.OIDC.ExtraParams { | ||||||
|  | 		extras = append(extras, oauth2.SetAuthURLParam(k, v)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	authURL := h.oauth2Config.AuthCodeURL(stateStr, extras...) | ||||||
| 	log.Debug().Msgf("Redirecting to %s for authentication", authURL) | 	log.Debug().Msgf("Redirecting to %s for authentication", authURL) | ||||||
| 
 | 
 | ||||||
| 	ctx.Redirect(http.StatusFound, authURL) | 	ctx.Redirect(http.StatusFound, authURL) | ||||||
| @ -187,6 +194,29 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// If AllowedDomains is provided, check that the authenticated principal ends with @<alloweddomain>. | ||||||
|  | 	if len(h.cfg.OIDC.AllowedDomains) > 0 { | ||||||
|  | 		if at := strings.LastIndex(claims.Email, "@"); at < 0 || | ||||||
|  | 			!IsStringInSlice(h.cfg.OIDC.AllowedDomains, claims.Email[at+1:]) { | ||||||
|  | 			log.Error().Msg("authenticated principal does not match any allowed domain") | ||||||
|  | 			ctx.String( | ||||||
|  | 				http.StatusBadRequest, | ||||||
|  | 				"unauthorized principal (domain mismatch)", | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// If AllowedUsers is provided, check that the authenticated princial is part of that list. | ||||||
|  | 	if len(h.cfg.OIDC.AllowedUsers) > 0 && | ||||||
|  | 		!IsStringInSlice(h.cfg.OIDC.AllowedUsers, claims.Email) { | ||||||
|  | 		log.Error().Msg("authenticated principal does not match any allowed user") | ||||||
|  | 		ctx.String(http.StatusBadRequest, "unauthorized principal (user mismatch)") | ||||||
|  | 
 | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// retrieve machinekey from state cache | 	// retrieve machinekey from state cache | ||||||
| 	machineKeyIf, machineKeyFound := h.registrationCache.Get(state) | 	machineKeyIf, machineKeyFound := h.registrationCache.Get(state) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								poll.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								poll.go
									
									
									
									
									
								
							| @ -20,6 +20,10 @@ const ( | |||||||
| 	updateCheckInterval = 10 * time.Second | 	updateCheckInterval = 10 * time.Second | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | type contextKey string | ||||||
|  | 
 | ||||||
|  | const machineNameContextKey = contextKey("machineName") | ||||||
|  | 
 | ||||||
| // PollNetMapHandler takes care of /machine/:id/map | // PollNetMapHandler takes care of /machine/:id/map | ||||||
| // | // | ||||||
| // This is the busiest endpoint, as it keeps the HTTP long poll that updates | // This is the busiest endpoint, as it keeps the HTTP long poll that updates | ||||||
| @ -261,7 +265,7 @@ func (h *Headscale) PollNetMapStream( | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ctx := context.WithValue(ctx.Request.Context(), "machineName", machine.Hostname) | 		ctx := context.WithValue(ctx.Request.Context(), machineNameContextKey, machine.Hostname) | ||||||
| 
 | 
 | ||||||
| 		ctx, cancel := context.WithCancel(ctx) | 		ctx, cancel := context.WithCancel(ctx) | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| @ -565,12 +569,12 @@ func (h *Headscale) scheduledPollWorker( | |||||||
| 
 | 
 | ||||||
| 	defer closeChanWithLog( | 	defer closeChanWithLog( | ||||||
| 		updateChan, | 		updateChan, | ||||||
| 		fmt.Sprint(ctx.Value("machineName")), | 		fmt.Sprint(ctx.Value(machineNameContextKey)), | ||||||
| 		"updateChan", | 		"updateChan", | ||||||
| 	) | 	) | ||||||
| 	defer closeChanWithLog( | 	defer closeChanWithLog( | ||||||
| 		keepAliveChan, | 		keepAliveChan, | ||||||
| 		fmt.Sprint(ctx.Value("machineName")), | 		fmt.Sprint(ctx.Value(machineNameContextKey)), | ||||||
| 		"updateChan", | 		"updateChan", | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -81,6 +81,13 @@ service HeadscaleService { | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     rpc SetTags(SetTagsRequest) returns (SetTagsResponse) { | ||||||
|  |         option (google.api.http) = { | ||||||
|  |             post: "/api/v1/machine/{machine_id}/tags" | ||||||
|  |             body: "*" | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     rpc RegisterMachine(RegisterMachineRequest) returns (RegisterMachineResponse) { |     rpc RegisterMachine(RegisterMachineRequest) returns (RegisterMachineResponse) { | ||||||
|         option (google.api.http) = { |         option (google.api.http) = { | ||||||
|             post: "/api/v1/machine/register" |             post: "/api/v1/machine/register" | ||||||
| @ -110,6 +117,12 @@ service HeadscaleService { | |||||||
|             get: "/api/v1/machine" |             get: "/api/v1/machine" | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     rpc MoveMachine(MoveMachineRequest) returns (MoveMachineResponse) { | ||||||
|  |         option (google.api.http) = { | ||||||
|  |             post: "/api/v1/machine/{machine_id}/namespace" | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|     // --- Machine end --- |     // --- Machine end --- | ||||||
| 
 | 
 | ||||||
|     // --- Route start --- |     // --- Route start --- | ||||||
|  | |||||||
| @ -22,7 +22,6 @@ message Machine { | |||||||
|     string          name         = 6; |     string          name         = 6; | ||||||
|     Namespace namespace          = 7; |     Namespace namespace          = 7; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     google.protobuf.Timestamp last_seen              = 8; |     google.protobuf.Timestamp last_seen              = 8; | ||||||
|     google.protobuf.Timestamp last_successful_update = 9; |     google.protobuf.Timestamp last_successful_update = 9; | ||||||
|     google.protobuf.Timestamp expiry                 = 10; |     google.protobuf.Timestamp expiry                 = 10; | ||||||
| @ -32,6 +31,8 @@ message Machine { | |||||||
|     google.protobuf.Timestamp created_at = 12; |     google.protobuf.Timestamp created_at = 12; | ||||||
| 
 | 
 | ||||||
|     RegisterMethod register_method = 13; |     RegisterMethod register_method = 13; | ||||||
|  | 
 | ||||||
|  |     reserved 14 to 17; | ||||||
|     // google.protobuf.Timestamp updated_at = 14; |     // google.protobuf.Timestamp updated_at = 14; | ||||||
|     // google.protobuf.Timestamp deleted_at = 15; |     // google.protobuf.Timestamp deleted_at = 15; | ||||||
| 
 | 
 | ||||||
| @ -39,7 +40,10 @@ message Machine { | |||||||
|     // bytes endpoints      = 16; |     // bytes endpoints      = 16; | ||||||
|     // bytes enabled_routes = 17; |     // bytes enabled_routes = 17; | ||||||
| 
 | 
 | ||||||
|     string          given_name     = 18; |     repeated string forced_tags  = 18; | ||||||
|  |     repeated string invalid_tags = 19; | ||||||
|  |     repeated string valid_tags   = 20; | ||||||
|  |     string          given_name   = 21; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| message RegisterMachineRequest { | message RegisterMachineRequest { | ||||||
| @ -59,6 +63,15 @@ message GetMachineResponse { | |||||||
|     Machine machine = 1; |     Machine machine = 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | message SetTagsRequest { | ||||||
|  |     uint64          machine_id = 1; | ||||||
|  |     repeated string tags       = 2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | message SetTagsResponse { | ||||||
|  |     Machine machine = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| message DeleteMachineRequest { | message DeleteMachineRequest { | ||||||
|     uint64 machine_id = 1; |     uint64 machine_id = 1; | ||||||
| } | } | ||||||
| @ -91,6 +104,15 @@ message ListMachinesResponse { | |||||||
|     repeated Machine machines = 1; |     repeated Machine machines = 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | message MoveMachineRequest { | ||||||
|  |     uint64 machine_id = 1; | ||||||
|  |     string namespace  = 2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | message MoveMachineResponse { | ||||||
|  |     Machine machine = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| message DebugCreateMachineRequest { | message DebugCreateMachineRequest { | ||||||
|     string namespace       = 1; |     string namespace       = 1; | ||||||
|     string          key    = 2; |     string          key    = 2; | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								tools.go
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								tools.go
									
									
									
									
									
								
							| @ -1,13 +0,0 @@ | |||||||
| //go:build tools |  | ||||||
| // +build tools |  | ||||||
| 
 |  | ||||||
| package tools |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	_ "github.com/bufbuild/buf/cmd/buf" |  | ||||||
| 	_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway" |  | ||||||
| 	_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2" |  | ||||||
| 	_ "github.com/infobloxopen/protoc-gen-gorm" |  | ||||||
| 	_ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" |  | ||||||
| 	_ "google.golang.org/protobuf/cmd/protoc-gen-go" |  | ||||||
| ) |  | ||||||
							
								
								
									
										40
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								utils.go
									
									
									
									
									
								
							| @ -12,6 +12,7 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net" | 	"net" | ||||||
|  | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| @ -135,26 +136,29 @@ func encode( | |||||||
| 	return privKey.SealTo(*pubKey, b), nil | 	return privKey.SealTo(*pubKey, b), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (h *Headscale) getAvailableIPs() (ips MachineAddresses, err error) { | func (h *Headscale) getAvailableIPs() (MachineAddresses, error) { | ||||||
|  | 	var ips MachineAddresses | ||||||
|  | 	var err error | ||||||
| 	ipPrefixes := h.cfg.IPPrefixes | 	ipPrefixes := h.cfg.IPPrefixes | ||||||
| 	for _, ipPrefix := range ipPrefixes { | 	for _, ipPrefix := range ipPrefixes { | ||||||
| 		var ip *netaddr.IP | 		var ip *netaddr.IP | ||||||
| 		ip, err = h.getAvailableIP(ipPrefix) | 		ip, err = h.getAvailableIP(ipPrefix) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return ips, err | ||||||
| 		} | 		} | ||||||
| 		ips = append(ips, *ip) | 		ips = append(ips, *ip) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return | 	return ips, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetIPPrefixEndpoints(na netaddr.IPPrefix) (network, broadcast netaddr.IP) { | func GetIPPrefixEndpoints(na netaddr.IPPrefix) (netaddr.IP, netaddr.IP) { | ||||||
|  | 	var network, broadcast netaddr.IP | ||||||
| 	ipRange := na.Range() | 	ipRange := na.Range() | ||||||
| 	network = ipRange.From() | 	network = ipRange.From() | ||||||
| 	broadcast = ipRange.To() | 	broadcast = ipRange.To() | ||||||
| 
 | 
 | ||||||
| 	return | 	return network, broadcast | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (h *Headscale) getAvailableIP(ipPrefix netaddr.IPPrefix) (*netaddr.IP, error) { | func (h *Headscale) getAvailableIP(ipPrefix netaddr.IPPrefix) (*netaddr.IP, error) { | ||||||
| @ -223,16 +227,6 @@ func (h *Headscale) getUsedIPs() (*netaddr.IPSet, error) { | |||||||
| 	return ipSet, nil | 	return ipSet, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func containsString(ss []string, s string) bool { |  | ||||||
| 	for _, v := range ss { |  | ||||||
| 		if v == s { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func tailNodesToString(nodes []*tailcfg.Node) string { | func tailNodesToString(nodes []*tailcfg.Node) string { | ||||||
| 	temp := make([]string, len(nodes)) | 	temp := make([]string, len(nodes)) | ||||||
| 
 | 
 | ||||||
| @ -282,9 +276,9 @@ func stringToIPPrefix(prefixes []string) ([]netaddr.IPPrefix, error) { | |||||||
| 	return result, nil | 	return result, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func containsIPPrefix(prefixes []netaddr.IPPrefix, prefix netaddr.IPPrefix) bool { | func contains[T string | netaddr.IPPrefix](ts []T, t T) bool { | ||||||
| 	for _, p := range prefixes { | 	for _, v := range ts { | ||||||
| 		if prefix == p { | 		if reflect.DeepEqual(v, t) { | ||||||
| 			return true | 			return true | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -330,3 +324,13 @@ func GenerateRandomStringDNSSafe(n int) (string, error) { | |||||||
| 
 | 
 | ||||||
| 	return str[:n], err | 	return str[:n], err | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func IsStringInSlice(slice []string, str string) bool { | ||||||
|  | 	for _, s := range slice { | ||||||
|  | 		if s == str { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user