├── tools ├── modules │ └── AksEdgeDeploy │ │ ├── AksEdgeModule.md │ │ ├── AksEdgeDeploy.png │ │ ├── AksEdgeSchema.png │ │ ├── aide-userconfig.puml │ │ ├── aksedge-dc.puml │ │ ├── AksEdgeDeploy.psd1 │ │ ├── aide-ucschema.json │ │ ├── README.md │ │ └── AksEdgeDeploy-AEC.ps1 ├── scripts │ ├── utils │ │ ├── Newtonsoft │ │ │ ├── Newtonsoft.Json.dll │ │ │ └── Newtonsoft.Json.Schema.dll │ │ ├── SchemaValidation.ps1 │ │ └── ExportModules.ps1 │ ├── AksEdgeKeyManagerExtension │ │ ├── README.md │ │ └── UpdateK3sConfigForKeyManager.ps1 │ ├── AksEdgeAzureSetup │ │ ├── AzureConfig.json │ │ ├── README.md │ │ ├── InstallArcForServer.ps1 │ │ └── AksEdgeAzureSetup-Test.ps1 │ ├── AksEdgeRemoteDeploy │ │ ├── README.md │ │ ├── AksEdgeUninstall.ps1 │ │ ├── AksEdgeRemoteDeploy.ps1 │ │ └── AksEdgeRemoteDeploy-Intune.ps1 │ ├── AksEdgeQuickStart │ │ ├── AksEdgeAdminOperationsForAio.ps1 │ │ ├── README.md │ │ ├── AksEdgeQuickStart.ps1 │ │ └── AksEdgeQuickStart-v2.ps1 │ └── network │ │ └── AksEdge-ListUsedIPv4s.ps1 ├── AksEdgePrompt-PS7.cmd ├── AksEdgePrompt.cmd ├── aide-userconfig.json ├── aio-aide-userconfig.json ├── aio-aksedge-config.json ├── aksedge-config.json └── AksEdgeShell.ps1 ├── samples ├── storage │ ├── nfs │ │ ├── pvc.yaml │ │ ├── class.yaml │ │ ├── pod.yaml │ │ ├── deployment.yaml │ │ └── rbac.yaml │ └── local-path-provisioner │ │ ├── pvc.yaml │ │ ├── pod.yaml │ │ └── local-path-storage.yaml ├── others │ ├── win-sample.yaml │ ├── win-sample-aspnetcore.yaml │ ├── linux-sample.yaml │ ├── metrics-server.yaml │ └── container-azm-ms-agentconfig.yml └── README.md ├── .github └── ISSUE_TEMPLATE │ ├── question.md │ ├── feedback.md │ ├── feature_request.md │ └── bug_report.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── .pipeline ├── e2e-test-pipeline.yml └── templates │ ├── matrix-generator.yml │ ├── e2e-linuxoffline.yml │ ├── e2e-linuxandwindows.yml │ └── e2e-linuxonline.yml ├── LICENSE ├── SUPPORT.md ├── CONTRIBUTING.md ├── tests └── E2E │ ├── utils.ps1 │ ├── e2e_basiclinuxonline_test.ps1 │ ├── e2e_basiclinuxoffline_test.ps1 │ └── e2e_basiclinuxandwindowsoffline_test.ps1 ├── SECURITY.md ├── README.md └── .gitignore /tools/modules/AksEdgeDeploy/AksEdgeModule.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AKS-Edge/HEAD/tools/modules/AksEdgeDeploy/AksEdgeModule.md -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/AksEdgeDeploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AKS-Edge/HEAD/tools/modules/AksEdgeDeploy/AksEdgeDeploy.png -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/AksEdgeSchema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AKS-Edge/HEAD/tools/modules/AksEdgeDeploy/AksEdgeSchema.png -------------------------------------------------------------------------------- /tools/scripts/utils/Newtonsoft/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AKS-Edge/HEAD/tools/scripts/utils/Newtonsoft/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /tools/scripts/utils/Newtonsoft/Newtonsoft.Json.Schema.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AKS-Edge/HEAD/tools/scripts/utils/Newtonsoft/Newtonsoft.Json.Schema.dll -------------------------------------------------------------------------------- /tools/AksEdgePrompt-PS7.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell -Command "Start-Process 'pwsh.exe' -ArgumentList '-noexit -ExecutionPolicy Bypass -File \"%~dp0\AksEdgeShell.ps1\"' -Verb runAs" 3 | -------------------------------------------------------------------------------- /tools/AksEdgePrompt.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell -Command "Start-Process 'powershell.exe' -ArgumentList '-noexit -ExecutionPolicy Bypass -File \"%~dp0\AksEdgeShell.ps1\"' -Verb runAs" 3 | -------------------------------------------------------------------------------- /samples/storage/nfs/pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: nfs-pvc 5 | namespace: default 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | storageClassName: nfs-client 10 | resources: 11 | requests: 12 | storage: 1Mi -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: AKS Question 4 | title: "[Question]" 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe scenario** 11 | A clear and concise description of what your scenario is. 12 | 13 | **Question** 14 | Your question 15 | -------------------------------------------------------------------------------- /samples/storage/local-path-provisioner/pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: local-path-pvc 5 | namespace: default 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | storageClassName: local-path 10 | resources: 11 | requests: 12 | storage: 128Mi -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feedback.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feedback 3 | about: AKS General Feedback 4 | title: "[Feedback]" 5 | labels: Feedback 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe your scenario** 11 | A clear and concise description of what your scenario is. 12 | 13 | **Feedback** 14 | Your feedback/comment 15 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/about-codeowners/ 2 | # for more info about CODEOWNERS file 3 | # 4 | # It uses the same pattern rule for gitignore file 5 | # https://git-scm.com/docs/gitignore#_pattern_format 6 | # 7 | 8 | # 9 | # For all file changes, github would automatically include the following people in the PRs. 10 | # 11 | 12 | * @azure/aks-iot 13 | -------------------------------------------------------------------------------- /samples/storage/nfs/class.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: nfs-client 5 | provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME' 6 | parameters: 7 | pathPattern: "" # waits for nfs.io/storage-path annotation, if not specified will accept as empty string. 8 | onDelete: delete -------------------------------------------------------------------------------- /tools/scripts/AksEdgeKeyManagerExtension/README.md: -------------------------------------------------------------------------------- 1 | # AksEdge KeyManager Extension setup scrip 2 | 3 | This directory contains the script use to setup the K3 configuration for AKS Edge Essential for Key Manager Extension. 4 | 5 | ## UpdateK3sConfigForKeyManager.ps1 6 | This script updates the k3s configuration to set the lifespan of a Service Account token to 24 hours. 7 | This only needs to be run once prior to install the KeyManaget extension for the first time. -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /samples/storage/nfs/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: volume-test 5 | namespace: default 6 | spec: 7 | nodeSelector: 8 | "kubernetes.io/os": linux 9 | containers: 10 | - name: volume-test 11 | image: nginx:stable-alpine 12 | imagePullPolicy: IfNotPresent 13 | volumeMounts: 14 | - name: volv 15 | mountPath: /data 16 | ports: 17 | - containerPort: 80 18 | volumes: 19 | - name: volv 20 | persistentVolumeClaim: 21 | claimName: nfs-pvc -------------------------------------------------------------------------------- /tools/scripts/AksEdgeAzureSetup/AzureConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "Azure" : { 3 | "SubscriptionName": "", 4 | "SubscriptionId": "", 5 | "TenantId":"", 6 | "ResourceGroupName": "arciot-rg", 7 | "ServicePrincipalName" : "arciot-sp", 8 | "Location" : "EastUS", 9 | "CustomLocationOID":"", 10 | "Auth": { 11 | "ServicePrincipalId" : "", 12 | "Password" : "" 13 | } 14 | }, 15 | "AksEdgeConfigFile": "" 16 | } -------------------------------------------------------------------------------- /samples/storage/local-path-provisioner/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: volume-test 5 | namespace: default 6 | spec: 7 | nodeSelector: 8 | "kubernetes.io/os": linux 9 | containers: 10 | - name: volume-test 11 | image: nginx:stable-alpine 12 | imagePullPolicy: IfNotPresent 13 | volumeMounts: 14 | - name: volv 15 | mountPath: /data 16 | ports: 17 | - containerPort: 80 18 | volumes: 19 | - name: volv 20 | persistentVolumeClaim: 21 | claimName: local-path-pvc -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature]" 5 | labels: feature-request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tools/scripts/utils/SchemaValidation.ps1: -------------------------------------------------------------------------------- 1 | function SchemaValidator { 2 | <# 3 | .DESCRIPTION 4 | Validates the json configuration against defined schema 5 | #> 6 | param ( 7 | [String]$schmeaPath, 8 | [String]$UserConfig 9 | ) 10 | 11 | Add-Type -Path "$PSScriptRoot\Newtonsoft\Newtonsoft.Json.dll" 12 | Add-Type -Path "$PSScriptRoot\Newtonsoft\Newtonsoft.Json.Schema.dll" 13 | 14 | $jsonString = $UserConfig | ConvertTo-Json 15 | $schemaString = Get-Content -Raw $schmeaPath 16 | 17 | $errorMessages = New-Object System.Collections.Generic.List[string] 18 | 19 | $retval = [Newtonsoft.Json.Schema.SchemaExtensions]::isValid([Newtonsoft.Json.Linq.JToken]::Parse($jsonString), [Newtonsoft.Json.Schema.JSchema]::Parse($schemaString), [ref]$errorMessages) 20 | if(-not $retval) { 21 | Write-Host $errorMessages 22 | } 23 | return $retval 24 | } -------------------------------------------------------------------------------- /tools/aide-userconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "SchemaVersion": "1.3", 3 | "Version": "1.0", 4 | "AksEdgeProduct": "AKS Edge Essentials - K3s", 5 | "AksEdgeProductUrl": "", 6 | "InstallOptions": { 7 | "InstallPath": "", 8 | "VhdxPath": "" 9 | }, 10 | "VSwitch": { 11 | "Name": "", 12 | "AdapterName": "" 13 | }, 14 | "Azure": { 15 | "SubscriptionName":"Visual Studio Enterprise Subscription", 16 | "SubscriptionId": "", 17 | "TenantId": "", 18 | "ResourceGroupName": "aksedge-rg", 19 | "ServicePrincipalName": "aksedge-sp", 20 | "Location": "EastUS", 21 | "CustomLocationOID":"", 22 | "Auth": { 23 | "ServicePrincipalId": "", 24 | "Password": "" 25 | }, 26 | "ConnectedMachineName": "" 27 | }, 28 | "AksEdgeConfigFile": "aksedge-config.json" 29 | } -------------------------------------------------------------------------------- /samples/others/win-sample.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: sample 5 | labels: 6 | app: sample 7 | spec: 8 | replicas: 1 9 | template: 10 | metadata: 11 | name: sample 12 | labels: 13 | app: sample 14 | spec: 15 | nodeSelector: 16 | "kubernetes.io/os": windows 17 | containers: 18 | - name: sample 19 | image: mcr.microsoft.com/dotnet/framework/samples:aspnetapp 20 | resources: 21 | limits: 22 | cpu: 1 23 | memory: 800M 24 | requests: 25 | cpu: .1 26 | memory: 300M 27 | ports: 28 | - containerPort: 80 29 | selector: 30 | matchLabels: 31 | app: sample 32 | --- 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: sample 37 | spec: 38 | type: NodePort 39 | ports: 40 | - protocol: TCP 41 | port: 80 42 | selector: 43 | app: sample -------------------------------------------------------------------------------- /tools/aio-aide-userconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "SchemaVersion": "1.3", 3 | "Version": "1.0", 4 | "AksEdgeProduct": "AKS Edge Essentials - K3s", 5 | "AksEdgeProductUrl": "https://download.microsoft.com/download/67fee208-b68d-47a3-81a5-454382df99a6/AksEdge-K3s-1.30.6.msi", 6 | "InstallOptions": { 7 | "InstallPath": "", 8 | "VhdxPath": "" 9 | }, 10 | "VSwitch": { 11 | "Name": "", 12 | "AdapterName": "" 13 | }, 14 | "Azure": { 15 | "SubscriptionName": "", 16 | "SubscriptionId": "", 17 | "TenantId": "", 18 | "ResourceGroupName": "", 19 | "ServicePrincipalName": "", 20 | "Location": "", 21 | "CustomLocationOID": "", 22 | "EnableWorkloadIdentity": true, 23 | "GatewayResourceId": "", 24 | "Auth": { 25 | "ServicePrincipalId": "", 26 | "Password": "" 27 | } 28 | }, 29 | "AksEdgeConfigFile": "aio-aksedge-config.json" 30 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Run command '...' 16 | 2. See error 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Environment (please complete the following information):** 25 | - AKS Edge Essentials Version [e.g. 3.22] 26 | - Kubernetes version [e.g. 1.24.3] 27 | - Windows Host OS (please complete the following information): 28 | - Edition: [e.g. Professional, IoT Enterprise, Server, etc] 29 | - Version: [e.g. build 17763] 30 | - Virtual Machine: [eg. Azure VM, Local VM, Other, None] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /samples/others/win-sample-aspnetcore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: sample-aspnetcore 5 | labels: 6 | app: sample-aspnetcore 7 | spec: 8 | replicas: 1 9 | template: 10 | metadata: 11 | name: sample-aspnetcore 12 | labels: 13 | app: sample-aspnetcore 14 | spec: 15 | nodeSelector: 16 | "kubernetes.io/os": windows 17 | containers: 18 | - name: sample-aspnetcore 19 | image: mcr.microsoft.com/dotnet/samples:aspnetapp 20 | resources: 21 | limits: 22 | cpu: 1 23 | memory: 800M 24 | requests: 25 | cpu: 1 26 | memory: 300M 27 | ports: 28 | - containerPort: 8080 29 | selector: 30 | matchLabels: 31 | app: sample-aspnetcore 32 | --- 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: sample-aspnetcore 37 | spec: 38 | type: NodePort 39 | ports: 40 | - protocol: TCP 41 | port: 8080 42 | selector: 43 | app: sample-aspnetcore -------------------------------------------------------------------------------- /tools/scripts/AksEdgeRemoteDeploy/README.md: -------------------------------------------------------------------------------- 1 | # AKS Edge Essentials Remote Deployment 2 | 3 | AksEdgeRemoteDeploy enables you to deploy the AKS Edge Essentials using AksEdgeDeploy module through Intune, Arc for Server channels. 4 | 5 | ## Via Intune 6 | 7 | 1. Update the [AksEdgeRemoteDeploy-Intune.ps1](AksEdgeRemoteDeploy-Intune.ps1) script with the required parameters in the `$jsonContent` Here string. 8 | 2. Deploy this script with the following the instructions available at [Use PowerShell scripts on Windows 10/11 devices in Intune](https://docs.microsoft.com/mem/intune/apps/intune-management-extension?msclkid=ed33bab9d07311eca7ecb4b9f790a046). 9 | 10 | ## Via Arc Enabled Servers - Custom Script Extenstion 11 | 12 | 1. Update the [AksEdgeRemoteDeploy.ps1](AksEdgeRemoteDeploy.ps1) script with the required parameters in the `$jsonContent` Here string. 13 | 2. Deploy this script with the following the instructions available at [Custom Script Extension for Windows](https://docs.microsoft.com/azure/virtual-machines/extensions/custom-script-windows). 14 | -------------------------------------------------------------------------------- /tools/aio-aksedge-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "SchemaVersion": "1.15", 3 | "Version": "1.0", 4 | "DeploymentType": "SingleMachineCluster", 5 | "Init": { 6 | "ServiceIPRangeSize": 10 7 | }, 8 | "Arc": { 9 | "ClusterName": "", 10 | "Location": null, 11 | "ResourceGroupName": null, 12 | "SubscriptionId": null, 13 | "TenantId": null, 14 | "ClientId": null, 15 | "ClientSecret": null 16 | }, 17 | "Network": { 18 | "NetworkPlugin": "flannel", 19 | "InternetDisabled": false, 20 | "Proxy": { 21 | "Http": null, 22 | "Https": null, 23 | "No": null 24 | } 25 | }, 26 | "User": { 27 | "AcceptEula": true, 28 | "AcceptOptionalTelemetry": true 29 | }, 30 | "Machines": [ 31 | { 32 | "LinuxNode": { 33 | "CpuCount": 4, 34 | "MemoryInMB": 10240, 35 | "DataSizeInGB": 40, 36 | "LogSizeInGB": 4 37 | } 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /.pipeline/e2e-test-pipeline.yml: -------------------------------------------------------------------------------- 1 | # E2E pipeline for AKS Iot 2 | 3 | trigger: none 4 | 5 | resources: 6 | repositories: 7 | - repository: AksEdge 8 | type: github 9 | endpoint: AksEdge-GithubConnection 10 | name: Azure/AKS-Edge 11 | ref: $(Build.SourceBranch) 12 | 13 | 14 | # Reference the MSI pipelines 15 | 16 | parameters: 17 | - name: TestGroup 18 | displayName: Test Group to execute 19 | type: string 20 | default: LinuxOffline 21 | values: 22 | - LinuxOffline 23 | - LinuxOnline 24 | - LinuxAndWindows 25 | - All 26 | jobs: 27 | - template: templates/matrix-generator.yml 28 | parameters: 29 | TestGroup: ${{ parameters.TestGroup }} 30 | - ${{ if or( eq(parameters.TestGroup, 'All'), eq(parameters.TestGroup, 'LinuxOffline')) }}: 31 | - template: templates/e2e-linuxoffline.yml 32 | - ${{ if or( eq(parameters.TestGroup, 'All'), eq(parameters.TestGroup, 'LinuxOnline')) }}: 33 | - template: templates/e2e-linuxonline.yml 34 | - ${{ if or( eq(parameters.TestGroup, 'All'), eq(parameters.TestGroup, 'LinuxAndWindows')) }}: 35 | - template: templates/e2e-linuxandwindows.yml 36 | -------------------------------------------------------------------------------- /tools/aksedge-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "SchemaVersion": "1.16", 3 | "Version": "1.0", 4 | "DeploymentType": "SingleMachineCluster", 5 | "Init": { 6 | "ServiceIPRangeSize": 10, 7 | "KmsPlugin":{ 8 | "Enable": false 9 | } 10 | }, 11 | "Arc": { 12 | "ClusterName": null, 13 | "Location": null, 14 | "ResourceGroupName": null, 15 | "SubscriptionId": null, 16 | "TenantId": null, 17 | "ClientId": null, 18 | "ClientSecret": null 19 | }, 20 | "Network": { 21 | "NetworkPlugin": "flannel", 22 | "InternetDisabled": false, 23 | "Proxy": { 24 | "Http": null, 25 | "Https": null, 26 | "No": null 27 | } 28 | }, 29 | "User": { 30 | "AcceptEula": true, 31 | "AcceptOptionalTelemetry": true 32 | }, 33 | "Machines": [ 34 | { 35 | "LinuxNode": { 36 | "CpuCount": 4, 37 | "MemoryInMB": 4096, 38 | "DataSizeInGB": 20 39 | } 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /tools/scripts/utils/ExportModules.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Sample script to export modules for remote deployment 3 | #> 4 | param( 5 | [String] $ExportDir = $((Get-Location).Path), 6 | [Switch] $AllTools, 7 | [Switch] $IncludeSamples 8 | )# Here string for the json content 9 | 10 | $RootDir = "$PSScriptRoot\..\..\.." 11 | $RootDir = (Resolve-Path -Path $RootDir).Path 12 | $filesToZip = @( 13 | "$RootDir\License" 14 | ) 15 | 16 | $ziptime = Get-Date -Format "yyMMdd-HHmm" 17 | if (-not (Test-Path "$ExportDir")) { 18 | Write-Host "Creating $ExportDir..." 19 | New-Item -Path "$ExportDir" -ItemType Directory | Out-Null 20 | } 21 | $suffix = $ziptime 22 | if ($IncludeSamples) { 23 | $filesToZip += @("$RootDir\samples") 24 | $suffix = "Samples-$ziptime" 25 | } 26 | if ($AllTools) { 27 | $filesToZip += @("$RootDir\tools") 28 | $suffix = "Tools-$suffix" 29 | } else { 30 | $filesToZip += @( 31 | "$RootDir\tools\modules\AksEdgeDeploy", 32 | "$RootDir\tools\*.*" 33 | ) 34 | } 35 | $zipFileName = "$ExportDir\aks-edge-$suffix.zip" 36 | Compress-Archive -Path $filesToZip -DestinationPath $zipFileName -Force 37 | Write-Host "$zipFileName" 38 | -------------------------------------------------------------------------------- /samples/storage/nfs/deployment.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | name: nfs-client-provisioner 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: nfs-client-provisioner 10 | strategy: 11 | type: Recreate 12 | template: 13 | metadata: 14 | labels: 15 | app: nfs-client-provisioner 16 | spec: 17 | serviceAccountName: nfs-client-provisioner 18 | nodeSelector: 19 | "kubernetes.io/os": linux 20 | containers: 21 | - name: nfs-client-provisioner 22 | image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 23 | volumeMounts: 24 | - name: nfs-client-root 25 | mountPath: /var/persistentvolumes 26 | env: 27 | - name: PROVISIONER_NAME 28 | value: k8s-sigs.io/nfs-subdir-external-provisioner 29 | - name: NFS_SERVER 30 | value: 31 | - name: NFS_PATH 32 | value: 33 | volumes: 34 | - name: nfs-client-root 35 | nfs: 36 | server: 37 | path: -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 2 | 3 | Samples are direct from the feature teams and we welcome your input on issues and suggestions for new samples. If you would like to see new coverage or have feedback, please consider contributing. You can edit the existing content, add new content, or simply create new issues. We’ll take a look at your suggestions and will work together to incorporate them into the docs. 4 | 5 | > **Note**: 6 | > When contributing, make sure you are contributing from a **develop** branch with clear branch naming and description of the PR. Your contribution will not be accepted if your PR is coming from the master branch and has no clear guidance. 7 | 8 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. 9 | 10 | This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. -------------------------------------------------------------------------------- /.pipeline/templates/matrix-generator.yml: -------------------------------------------------------------------------------- 1 | # Template for the matrix generator 2 | 3 | parameters: 4 | - name: TestGroup 5 | displayName: Test Group to execute 6 | 7 | jobs: 8 | - job: mtrxgenerator 9 | pool: 10 | vmImage: 'ubuntu-latest' 11 | steps: 12 | - checkout: self 13 | clean: true 14 | fetchDepth: 1 15 | - bash: | 16 | # Use the json file to get the values of params passed to the MSI pipeline 17 | # Install jq 18 | sudo apt-get update 19 | sudo apt-get install jq -y 20 | 21 | LinuxNodeOnline='false' 22 | LinuxNodeOffline='false' 23 | LinuxAndWindows='false' 24 | 25 | if [ "${{ parameters.TestGroup }}" == "All" ]; then 26 | LinuxNodeOnline='true' 27 | LinuxNodeOffline='true' 28 | LinuxAndWindows='true' 29 | elif [ "${{ parameters.TestGroup }}" == "LinuxOffline" ]; then 30 | LinuxNodeOffline='true' 31 | elif [ "${{ parameters.TestGroup }}" == "LinuxOnline" ]; then 32 | LinuxNodeOnline='true' 33 | elif [ "${{ parameters.TestGroup }}" == "LinuxAndWindows" ]; then 34 | LinuxAndWindows='true' 35 | fi 36 | 37 | echo "LinuxOffline: $LinuxNodeOffline" 38 | echo "LinuxOnline: $LinuxNodeOnline" 39 | echo "LinuxAndWindows: $LinuxAndWindows" 40 | 41 | echo "##vso[task.setVariable variable=LinuxNodeOffline;isOutput=true]$LinuxNodeOffline" 42 | echo "##vso[task.setVariable variable=LinuxNodeOnline;isOutput=true]$LinuxNodeOnline" 43 | echo "##vso[task.setVariable variable=LinuxAndWindows;isOutput=true]$LinuxAndWindows" 44 | 45 | name: mtrx 46 | -------------------------------------------------------------------------------- /tools/scripts/AksEdgeAzureSetup/README.md: -------------------------------------------------------------------------------- 1 | # AksEdge Azure Setup 2 | 3 | AksEdgeAzureSetup enables you to configure your Azure subscription for the use of Arc for Servers and Arc for Kubernetes for AKS Edge Essentials. 4 | 5 | Run the script `AksEdgeAzureSetup.ps1` in the `tools\scripts\AksEdgeAzureSetup` directory to 6 | 7 | * setup your Azure subscription 8 | * create the resource group 9 | * setup the required extensions and 10 | * create the service principal with minimal privileges listed below 11 | * `Azure Connected Machine Onboarding` 12 | * `Kubernetes Cluster - Azure Arc Onboarding` 13 | 14 | You will need to login for Azure CLI interactively for the first time to create the service principal. This step is required to be run only once per subscription. 15 | 16 | ```powershell 17 | # prompts for interactive login for serviceprincipal creation with minimal privileges 18 | .\AksEdgeAzureSetup.ps1 .\AzureConfig.json 19 | ``` 20 | 21 | If you require to create the service principal with `Contributor` role at the resource group level, you can add the `-spContributorRole` switch. 22 | 23 | ```powershell 24 | # creates service principal with Contributor role at resource group level 25 | .\AksEdgeAzureSetup.ps1 .\AzureConfig.json -spContributorRole 26 | ``` 27 | 28 | To, reset an already existing service principal, use `-spCredReset`. Reset should be used cautiously. 29 | 30 | ```powershell 31 | # resets the existing service principal 32 | .\AksEdgeAzureSetup.ps1 .\AzureConfig.json -spCredReset 33 | ``` 34 | 35 | Test the credentials with 36 | 37 | ```powershell 38 | # you can test the creds with 39 | .\AksEdgeAzureSetup-Test.ps1 .\AzureConfig.json 40 | ``` 41 | -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/aide-userconfig.puml: -------------------------------------------------------------------------------- 1 | @startjson AksEdgeDeploy 2 | 22 | #highlight "SchemaVersion" 23 | { 24 | "SchemaVersion":"1.3", 25 | "Version":"1.0", 26 | "AksEdgeProduct" : [ 27 | "AKS Edge Essentials - K8s", 28 | "AKS Edge Essentials - K3s" 29 | ], 30 | "AksEdgeProductUrl" : "URL", 31 | "Azure":{ 32 | "ClusterName":"String", 33 | "SubscriptionName":"String", 34 | "SubscriptionId": "GUID", 35 | "TenantId":"GUID", 36 | "ResourceGroupName": "String", 37 | "ServicePrincipalName" : "String", 38 | "Location" : "String", 39 | "CustomLocationOID":"GUID", 40 | "Auth": { 41 | "ServicePrincipalId" : "GUID", 42 | "Password" : "String" 43 | }, 44 | "//EnableWorkloadIdentity//" : "Boolean", 45 | "//EnableKeyManagement//" : "Boolean", 46 | "//GatewayResourceId//": "String", 47 | "ConnectedMachineName": "String" 48 | } 49 | , 50 | "InstallOptions":{ 51 | "InstallPath":"String", 52 | "VhdxPath":"String" 53 | } 54 | , 55 | "VSwitch": { 56 | "Name": "String", 57 | "AdapterName": "String" 58 | } 59 | , 60 | "AksEdgeConfigFile":"String", 61 | "AksEdgeConfig":{ 62 | "ref" :"aksedge-config.json" 63 | } 64 | } 65 | @endjson -------------------------------------------------------------------------------- /tests/E2E/utils.ps1: -------------------------------------------------------------------------------- 1 | function Get-WindowsVmIpAddress 2 | { 3 | $env:WSSD_CONFIG_PATH="c:\programdata\aksedge\protected\.wssd\cloudconfig" 4 | $WindowsVmTag="eb28e4f7-6522-4c33-a531-cfedf24b08e6" 5 | $IdLine = & 'C:\Program Files\aksedge\nodectl' network vnic list --query "[?tags.keys(@).contains(@,'$WindowsVmTag')]" | Select-String -Pattern "ipaddress:" 6 | $vmIp = ($IdLine -split ":")[1].Trim() 7 | 8 | return $vmIP 9 | } 10 | 11 | function Invoke-WindowsSSH 12 | { 13 | param ( 14 | [Parameter(Mandatory)] 15 | [String] $command 16 | ) 17 | 18 | $vmIP = Get-WindowsVmIpAddress 19 | 20 | try 21 | { 22 | $sshPrivKey = New-SshPrivateKey 23 | 24 | & ssh.exe -o LogLevel=ERROR -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectionAttempts=10 -o ConnectTimeout=30 -o PasswordAuthentication=no -i "$sshPrivKey" "aksedge-user@$vmIp" $command 25 | } 26 | finally 27 | { 28 | Remove-Item -Path $sshPrivKey -Force -ErrorAction SilentlyContinue 29 | } 30 | } 31 | 32 | function New-SshPrivateKey 33 | { 34 | 35 | $SshPrivateKey = $([io.Path]::Combine("C:\ProgramData\AksEdge\protected\.sshkey", "id_ecdsa")) 36 | if(!(Test-Path -Path $SshPrivateKey)) 37 | { 38 | Throw $("'$SshPrivateKey' is not found") 39 | } 40 | 41 | $TempFile = New-TemporaryFile 42 | Copy-Item $SshPrivateKey $TempFile 43 | 44 | $CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name 45 | $NewOwner = New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList $CurrentUser 46 | 47 | $acl = Get-Acl $TempFile 48 | $acl.SetOwner($NewOwner) 49 | $acl.SetAccessRuleProtection($true, $false) 50 | $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($NewOwner, "FullControl", "allow") 51 | $acl.AddAccessRule($rule) 52 | $acl | Set-Acl 53 | 54 | return $TempFile 55 | } 56 | -------------------------------------------------------------------------------- /samples/others/linux-sample.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: azure-vote-back 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: azure-vote-back 11 | template: 12 | metadata: 13 | labels: 14 | app: azure-vote-back 15 | spec: 16 | nodeSelector: 17 | "kubernetes.io/os": linux 18 | containers: 19 | - name: azure-vote-back 20 | image: azurek8ssamples.azurecr.io/marketplaceimages/azure-vote-back:latest 21 | env: 22 | - name: ALLOW_EMPTY_PASSWORD 23 | value: "yes" 24 | ports: 25 | - containerPort: 6379 26 | name: redis 27 | --- 28 | apiVersion: v1 29 | kind: Service 30 | metadata: 31 | name: azure-vote-back 32 | spec: 33 | ports: 34 | - port: 6379 35 | selector: 36 | app: azure-vote-back 37 | --- 38 | apiVersion: apps/v1 39 | kind: Deployment 40 | metadata: 41 | name: azure-vote-front 42 | spec: 43 | replicas: 1 44 | selector: 45 | matchLabels: 46 | app: azure-vote-front 47 | strategy: 48 | rollingUpdate: 49 | maxSurge: 1 50 | maxUnavailable: 1 51 | minReadySeconds: 5 52 | template: 53 | metadata: 54 | labels: 55 | app: azure-vote-front 56 | spec: 57 | nodeSelector: 58 | "kubernetes.io/os": linux 59 | containers: 60 | - name: azure-vote-front 61 | image: azurek8ssamples.azurecr.io/marketplaceimages/azure-vote-front:latest 62 | ports: 63 | - containerPort: 80 64 | resources: 65 | requests: 66 | cpu: 250m 67 | limits: 68 | cpu: 500m 69 | env: 70 | - name: REDIS 71 | value: "azure-vote-back" 72 | --- 73 | apiVersion: v1 74 | kind: Service 75 | metadata: 76 | name: azure-vote-front 77 | spec: 78 | type: LoadBalancer 79 | ports: 80 | - port: 80 81 | selector: 82 | app: azure-vote-front -------------------------------------------------------------------------------- /tools/scripts/AksEdgeRemoteDeploy/AksEdgeUninstall.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Sample script to setup Azure subscription for Arc for Kubernetes Connection 3 | #> 4 | #Requires -RunAsAdministrator 5 | 6 | if (! [Environment]::Is64BitProcess) { 7 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 8 | exit -1 9 | } 10 | # Here string for the json content 11 | $installDir = "C:\AksEdgeScript" 12 | 13 | if (-not (Test-Path "$installDir\Scripts")) { 14 | Write-Host "Error: $installDir\Scripts not found." -ForegroundColor Red 15 | exit -1 16 | } 17 | 18 | $aksjson = (Get-ChildItem -Path "$installDir\Scripts" -Filter aide-userconfig.json -Recurse).FullName 19 | $starttime = Get-Date 20 | $transcriptFile = "$PSScriptRoot\aksedgedlog-uninstall-$($starttime.ToString("yyMMdd-HHmm")).txt" 21 | Start-Transcript -Path $transcriptFile 22 | # Load the modules 23 | $modulePath = (Get-ChildItem -Path "$installDir\Scripts" -Filter AksEdgeDeploy -Recurse).FullName | Split-Path -Parent 24 | if (!(($env:PSModulePath).Contains($modulePath))) { 25 | $env:PSModulePath = "$modulePath;$env:PSModulePath" 26 | } 27 | Write-Host "Loading AksEdgeDeploy module.." 28 | Import-Module AksEdgeDeploy.psd1 -Force 29 | Set-AideUserConfig $aksjson 30 | Write-Host ">> Disconnecting from Arc" 31 | Disconnect-AideArcServer 32 | Disconnect-AideArcKubernetes 33 | Write-Host ">> Removing cluster deployment" 34 | Remove-AideDeployment 35 | Write-Host ">> Removing external switches if any" 36 | Remove-AideVmSwitch 37 | Write-Host ">> Removing AksEdge installation" 38 | Remove-AideMsi 39 | $regkeyentry = Get-Item -Path HKLM:\SOFTWARE\AksEdgeScript 40 | if ($regkeyentry) { 41 | Write-Host ">> Removing reg keys" 42 | Remove-Item -Path HKLM:\SOFTWARE\AksEdgeScript -Recurse -Force | Out-Null 43 | } 44 | $endtime = Get-Date 45 | $duration = ($endtime - $starttime) 46 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 47 | Stop-Transcript | Out-Null 48 | exit 0 -------------------------------------------------------------------------------- /tools/scripts/AksEdgeKeyManagerExtension/UpdateK3sConfigForKeyManager.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | 4 | <# 5 | This script updates the AKS Edge Essential K3s configuration to set the lifespan of a Service Account token to 24 hours. 6 | This only needs to be run once prior to install the KeyManaget extension for the first time. 7 | #> 8 | 9 | 10 | <# 11 | A wrapper around Invoke-AksEdgeNodeCommand to throw an exception if an error occurs. 12 | #> 13 | function Invoke-AksEdgeNodeCmd 14 | { 15 | param( 16 | [ValidateNotNullOrEmpty()] 17 | [string] $command, 18 | [switch] $ignoreError = $false 19 | ) 20 | 21 | $response = Invoke-AksEdgeNodeCommand $command -ignoreError:$ignoreError 22 | if ($LASTEXITCODE -eq 0) 23 | { 24 | return $response 25 | } 26 | throw "Invoke-AksEdgeNodeCommand `"$command`" failed." 27 | 28 | } 29 | 30 | #Requires -RunAsAdministrator 31 | 32 | Import-Module AksEdge 33 | 34 | $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop 35 | $VerbosePreference = [System.Management.Automation.ActionPreference]::Continue 36 | 37 | 38 | Write-Verbose "Updating k3s-config.yml" 39 | Invoke-AksEdgeNodeCmd -command "sudo cat /var/.eflow/config/k3s/k3s-config.yml | tee /home/aksedge-user/k3s-config.yml | tee /home/aksedge-user/k3s-config.yml.working > /dev/null" 40 | Invoke-AksEdgeNodeCmd -command "sudo sed -i '/kube-apiserver-arg:/a\ - service-account-max-token-expiration=24h00m0s\' /home/aksedge-user/k3s-config.yml" 41 | Invoke-AksEdgeNodeCmd -command "sudo sed -i '/kube-apiserver-arg:/a\ - service-account-extend-token-expiration=false\' /home/aksedge-user/k3s-config.yml" 42 | Invoke-AksEdgeNodeCmd -command "sudo cp /home/aksedge-user/k3s-config.yml /var/.eflow/config/k3s/k3s-config.yml" 43 | 44 | Write-Verbose "Restarting k3 service with updated configuration" 45 | Invoke-AksEdgeNodeCmd -command "sudo systemctl daemon-reload" 46 | Invoke-AksEdgeNodeCmd -command "sudo systemctl restart k3s.service" 47 | 48 | Write-Verbose "Successfully restarted k3 service with updated configuration" 49 | 50 | -------------------------------------------------------------------------------- /samples/storage/nfs/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: nfs-client-provisioner 5 | # replace with namespace where provisioner is deployed 6 | namespace: default 7 | --- 8 | kind: ClusterRole 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | metadata: 11 | name: nfs-client-provisioner-runner 12 | rules: 13 | - apiGroups: [""] 14 | resources: ["nodes"] 15 | verbs: ["get", "list", "watch"] 16 | - apiGroups: [""] 17 | resources: ["persistentvolumes"] 18 | verbs: ["get", "list", "watch", "create", "delete"] 19 | - apiGroups: [""] 20 | resources: ["persistentvolumeclaims"] 21 | verbs: ["get", "list", "watch", "update"] 22 | - apiGroups: ["storage.k8s.io"] 23 | resources: ["storageclasses"] 24 | verbs: ["get", "list", "watch"] 25 | - apiGroups: [""] 26 | resources: ["events"] 27 | verbs: ["create", "update", "patch"] 28 | --- 29 | kind: ClusterRoleBinding 30 | apiVersion: rbac.authorization.k8s.io/v1 31 | metadata: 32 | name: run-nfs-client-provisioner 33 | subjects: 34 | - kind: ServiceAccount 35 | name: nfs-client-provisioner 36 | # replace with namespace where provisioner is deployed 37 | namespace: default 38 | roleRef: 39 | kind: ClusterRole 40 | name: nfs-client-provisioner-runner 41 | apiGroup: rbac.authorization.k8s.io 42 | --- 43 | kind: Role 44 | apiVersion: rbac.authorization.k8s.io/v1 45 | metadata: 46 | name: leader-locking-nfs-client-provisioner 47 | # replace with namespace where provisioner is deployed 48 | namespace: default 49 | rules: 50 | - apiGroups: [""] 51 | resources: ["endpoints"] 52 | verbs: ["get", "list", "watch", "create", "update", "patch"] 53 | --- 54 | kind: RoleBinding 55 | apiVersion: rbac.authorization.k8s.io/v1 56 | metadata: 57 | name: leader-locking-nfs-client-provisioner 58 | # replace with namespace where provisioner is deployed 59 | namespace: default 60 | subjects: 61 | - kind: ServiceAccount 62 | name: nfs-client-provisioner 63 | # replace with namespace where provisioner is deployed 64 | namespace: default 65 | roleRef: 66 | kind: Role 67 | name: leader-locking-nfs-client-provisioner 68 | apiGroup: rbac.authorization.k8s.io 69 | -------------------------------------------------------------------------------- /tools/AksEdgeShell.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | AksEdgeShell.ps1 3 | Validates and loads the config file and imports the bootstrap scripts 4 | #> 5 | #Requires -RunAsAdministrator 6 | New-Variable -Name gAksEdgeShellVersion -Value "1.0.240904.1500" -Option Constant -ErrorAction SilentlyContinue 7 | if (! [Environment]::Is64BitProcess) { 8 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 9 | exit -1 10 | } 11 | 12 | $aksjson = "$PSScriptRoot\aide-userconfig.json" 13 | $aksjson = (Resolve-Path -Path $aksjson).Path 14 | Push-Location $PSScriptRoot 15 | 16 | $modulePath = Split-Path -Path $((Get-ChildItem $PSScriptRoot -recurse -Filter AksEdgeDeploy).FullName) -Parent 17 | if (!(($env:PSModulePath).Contains($modulePath))) { 18 | $env:PSModulePath = "$modulePath;$env:PSModulePath" 19 | } 20 | 21 | #remove AksEdgeDeploy module if already loaded 22 | if (Get-Module -Name AksEdgeDeploy -ErrorAction SilentlyContinue) { 23 | Remove-Module -Name AksEdgeDeploy -Force -ErrorAction SilentlyContinue 24 | } 25 | 26 | Write-Host "Loading AksEdgeDeploy module from $modulePath.." -ForegroundColor Cyan 27 | Import-Module AksEdgeDeploy.psd1 -Force 28 | $aideVersion = (Get-Module -Name AksEdgeDeploy).Version.ToString() 29 | Get-AideHostPcInfo 30 | 31 | $retval = Test-AideMsiInstall 32 | Write-Host "AksEdgeShell version `t: $gAksEdgeShellVersion" 33 | Write-Host "AksEdgeDeploy version `t: $aideVersion" 34 | 35 | $feature = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V 36 | if ($feature.State -ne "Enabled") { 37 | Write-Host "Hyper-V is disabled." -ForegroundColor Red 38 | if ($retval) { 39 | Write-Host "Running Install-AksEdgeHostFeatures (may reboot to enable Hyper-V)" -ForegroundColor Cyan 40 | if (!(Install-AksEdgeHostFeatures)) { return $false } 41 | } 42 | } else { 43 | Write-Host "Hyper-V is enabled" -ForegroundColor Green 44 | } 45 | 46 | 47 | Set-AideUserConfig $aksjson | Out-Null 48 | if (Test-AideDeployment) { 49 | Write-Host "AksEdge Cluster is already deployed" -ForegroundColor Green 50 | $wssdStatus = (Get-Service -Name WssdAgent).Status 51 | if ($wssdStatus -ne 'Running') { 52 | Write-Host "Error: WssdAgent is not running" -ForegroundColor Red 53 | Write-Host "Attempting to start wssdagent" 54 | Start-Service -Name WssdAgent 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | # AKS Edge Essentials Samples 2 | 3 | ## Quickstart Samples 4 | 5 | | Name | Description | 6 | |----------------|------------------| 7 | | [linux-sample](./others/linux-sample.yaml) | Basic Linux voting .NET sample app. For more information, check [AKS Voting App sample](https://learn.microsoft.com/en-us/samples/azure-samples/aks-voting-app/aks-voting-app/) . | 8 | | [windows-sample](./others/win-sample.yaml) | Basic Windows ASP NET sample app. For more information, check [AKS Windows App sample](https://learn.microsoft.com/en-us/azure/aks/hybrid/deploy-windows-application/) . | 9 | | [metrics-server](./others/metrics-server.yaml) | Resource metrics are collected by the lightweight, in-memory metrics-server component. Metrics-server discovers nodes and queries each one's kubelet for CPU and memory usage. For more information, check [AKS Monitoring](https://github.com/Azure/aks-engine/blob/master/docs/topics/monitoring.md) . | 10 | 11 | For more samples, labs, and workshops, please refer to [AKS-Edge-Labs GitHub](https://github.com/Azure/AKS-Edge-Labs/tree/main/Samples). 12 | 13 | ## Support 14 | 15 | Support through issues on this repository is provided on a **best-effort basis** for issues that are reproducible following our [**Bug Guidance**](./../README.md#bug-guidance). To receive urgent support, you must file a support request through official Azure support channels, as urgent support is explicitly out of the scope of this repository's objectives. 16 | 17 | ## Contributing 18 | These samples are direct from the feature teams and we welcome your input on issues and suggestions for new samples. If you would like to see new coverage or have feedback, please consider contributing. You can edit the existing content, add new content, or simply create new issues. We’ll take a look at your suggestions and will work together to incorporate them into the docs. 19 | 20 | This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 21 | 22 | > **Note**: 23 | > When contributing, make sure you are contributing from the **develop** branch and not the master branch. Your contribution will not be accepted if your PR is coming from the master branch. 24 | 25 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. 26 | 27 | This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /tools/scripts/AksEdgeQuickStart/AksEdgeAdminOperationsForAio.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Script for setting up Admin operations for AIO-AKSEE 3 | #> 4 | param( 5 | [ValidateNotNullOrEmpty()] 6 | [String] $SubscriptionId, 7 | [ValidateNotNullOrEmpty()] 8 | [String] $Location, 9 | [ValidateNotNullOrEmpty()] 10 | [String] $ResourceGroupName 11 | ) 12 | #Requires -RunAsAdministrator 13 | New-Variable -Name gAksEdgeAdminOperationsForAioVersion -Value "1.0.241118.1500" -Option Constant -ErrorAction SilentlyContinue 14 | 15 | # Validate az cli version. 16 | try { 17 | $azRequiredMinVersion = "2.64.0" 18 | $azVersion = (az version)[1].Split(":")[1].Split('"')[1] 19 | if ($azVersion -lt $azRequiredMinVersion){ 20 | Write-Host "Installed Azure CLI version $azVersion is older than $azRequiredMinVersion. Please upgrade Azure CLI and retry." -ForegroundColor Red 21 | exit -1 22 | } 23 | } 24 | catch { 25 | Write-Host "Please install Azure CLI version $azRequiredMinVersion or newer and retry." -ForegroundColor Red 26 | exit -1 27 | } 28 | 29 | # Ensure logged into Azure 30 | $azureLogin = az account show 31 | if ( $null -eq $azureLogin){ 32 | Write-Host "Please login to azure via `az login` and retry." -ForegroundColor Red 33 | exit -1 34 | } 35 | 36 | # Set the azure subscription 37 | Write-Host "Set subscription to $SubscriptionId" 38 | $errOut = $($retVal = & {az account set -s $SubscriptionId}) 2>&1 39 | if ($LASTEXITCODE -ne 0) 40 | { 41 | throw "Error setting Subscription ($SubscriptionId): $errOut" 42 | } 43 | 44 | # Create resource group if needed 45 | Write-Host "Verify/Create resource group $ResourceGroupName" 46 | $errOut = $($rgExists = & {az group show --resource-group $ResourceGroupName}) 2>&1 47 | if ($null -eq $rgExists) { 48 | Write-Host "Creating resource group: $ResourceGroupName" -ForegroundColor Cyan 49 | $errOut = $($retVal = & {az group create --location $Location --resource-group $ResourceGroupName --subscription $SubscriptionId}) 2>&1 50 | if ($LASTEXITCODE -ne 0) 51 | { 52 | throw "Error creating ResourceGroup ($ResourceGroupName): $errOut" 53 | } 54 | } 55 | 56 | # Register the required resource providers 57 | Write-Host "Verify/Register the required resource providers" -ForegroundColor Cyan 58 | $resourceProviders = 59 | @( 60 | "Microsoft.ExtendedLocation", 61 | "Microsoft.Kubernetes", 62 | "Microsoft.KubernetesConfiguration" 63 | ) 64 | foreach($rp in $resourceProviders) 65 | { 66 | $errOut = $($obj = & {az provider show -n $rp | ConvertFrom-Json}) 2>&1 67 | if ($LASTEXITCODE -ne 0) 68 | { 69 | throw "Error querying provider $rp : $errOut" 70 | } 71 | 72 | if ($obj.registrationState -eq "Registered") 73 | { 74 | continue 75 | } 76 | 77 | $errOut = $($retVal = & {az provider register -n $rp}) 2>&1 78 | if ($LASTEXITCODE -ne 0) 79 | { 80 | throw "Error registering provider $rp : $errOut" 81 | } 82 | } 83 | 84 | # Get CustomLocationOid 85 | Write-Host "Query CustomLocationOid" 86 | $customLocationsAppId = "bc313c14-388c-4e7d-a58e-70017303ee3b" 87 | $errOut = $($objectId = & {az ad sp show --id $customLocationsAppId --query id -o tsv}) 2>&1 88 | if ($null -eq $objectId) 89 | { 90 | throw "Error querying ObjectId for CustomLocationsAppId : $errOut" 91 | } 92 | Write-Host "CustomLocationOid - $objectId" -------------------------------------------------------------------------------- /tests/E2E/e2e_basiclinuxonline_test.ps1: -------------------------------------------------------------------------------- 1 | #Requires -RunAsAdministrator 2 | function Setup-BasicLinuxNodeOnline { 3 | param( 4 | # Test Parameters 5 | [String] 6 | $JsonTestParameters, 7 | 8 | [HashTable] 9 | # Optional parameters from the commandline 10 | $TestVar 11 | ) 12 | 13 | $retval = Start-AideWorkflow -jsonString $JsonTestParameters 14 | 15 | if($retval) { 16 | Write-Host "Deployment Successful" 17 | } else { 18 | throw "Deployment Failed" 19 | } 20 | 21 | $azureConfig = $(Get-AideUserConfig).Azure 22 | Write-Host $azureConfig 23 | 24 | if ($azureConfig.Auth.ServicePrincipalId -and $azureConfig.Auth.Password -and $azureConfig.TenantId){ 25 | $arcstatus = Initialize-AideArc 26 | if ($arcstatus) { 27 | Write-Host "Connecting to Azure Arc" 28 | if (Connect-AideArc) { 29 | Write-Host "Azure Arc connections successful." 30 | } else { 31 | throw "Error: Azure Arc connections failed" 32 | } 33 | } else { 34 | throw "Initializing Azure Arc failed" 35 | } 36 | } else { 37 | throw "No Auth info available. Skipping Arc Connection" 38 | } 39 | } 40 | 41 | function Cleanup-BasicLinuxNodeOnline { 42 | param( 43 | # Test Parameters 44 | [String] 45 | $JsonTestParameters, 46 | 47 | [HashTable] 48 | # Optional parameters from the commandline 49 | $TestVar 50 | ) 51 | 52 | Set-AideUserConfig -jsonString $JsonTestParameters 53 | 54 | Write-Host "Disconnecting from Arc" 55 | $retval = Disconnect-AideArcServer 56 | if($retval) { 57 | Write-Host "Arc Server disconnection successful" 58 | } else { 59 | throw "Arc server disconnection failed" 60 | } 61 | 62 | $retval = Disconnect-AideArcKubernetes 63 | if($retval) { 64 | Write-Host "Arc Server disconnection successful" 65 | } else { 66 | throw "Arc server disconnection failed" 67 | } 68 | 69 | $retval = Remove-AideDeployment 70 | 71 | if($retval) { 72 | Write-Host "Cleanup Successful" 73 | } else { 74 | throw "Cleanup Failed" 75 | } 76 | } 77 | 78 | function E2etest-BasicLinuxNodeOnline-TestOnlineClusterPodsReady { 79 | 80 | param( 81 | # Test Parameters 82 | [String] 83 | $JsonTestParameters, 84 | 85 | [HashTable] 86 | # Optional parameters from the commandline 87 | $TestVar 88 | ) 89 | 90 | Write-Host "Running kubectl on node" 91 | 92 | # Assuming the cluster is ready after this is done, let's prove whether it's good or not 93 | Get-AksEdgeKubeConfig -Confirm:$false 94 | 95 | $output = & 'c:\program files\AksEdge\kubectl\kubectl.exe' get pods -n azure-arc 96 | Assert-Equal $LastExitCode 0 97 | Write-Host "kubectl output:`n$output" 98 | 99 | $result = $($output -split '\r?\n' -replace '\s+', ';' | ConvertFrom-Csv -Delimiter ';') 100 | 101 | Write-Host "Status of azure-arc related pods" 102 | foreach ( $POD in $result ) 103 | { 104 | Write-Host "NAME: $($POD.NAME) STATUS: $($POD.STATUS)" 105 | } 106 | foreach ( $POD in $result ) 107 | { 108 | Assert-Equal $POD.STATUS 'Running' 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/E2E/e2e_basiclinuxoffline_test.ps1: -------------------------------------------------------------------------------- 1 | #Requires -RunAsAdministrator 2 | function Setup-BasicLinuxNodeOffline { 3 | param( 4 | # Test Parameters 5 | [String] 6 | $JsonTestParameters, 7 | 8 | [HashTable] 9 | # Optional parameters from the commandline 10 | $TestVar 11 | ) 12 | 13 | # Get Aide UserConfig 14 | 15 | $retval = Start-AideWorkflow -jsonString $JsonTestParameters 16 | 17 | if($retval) { 18 | Write-Host "Deployment Successful" 19 | } else { 20 | throw "Deployment Failed" 21 | } 22 | } 23 | 24 | function Cleanup-BasicLinuxNodeOffline { 25 | param( 26 | # Test Parameters 27 | [String] 28 | $JsonTestParameters, 29 | 30 | [HashTable] 31 | # Optional parameters from the commandline 32 | $TestVar 33 | ) 34 | 35 | $retval = Remove-AideDeployment 36 | 37 | if($retval) { 38 | Write-Host "Cleanup Successful" 39 | } else { 40 | throw "Cleanup Failed" 41 | } 42 | } 43 | 44 | function E2etest-BasicLinuxNodeOffline-TestOfflineClusterNodesReady { 45 | 46 | param( 47 | 48 | # Test Parameters 49 | [String] 50 | $JsonTestParameters, 51 | 52 | [HashTable] 53 | # Optional parameters from the commandline 54 | $TestVar 55 | ) 56 | 57 | Write-Host "Running kubectl on node" 58 | 59 | # Assuming the cluster is ready after this is done, let's prove whether it's good or not 60 | Get-AksEdgeKubeConfig -Confirm:$false 61 | 62 | $output = & 'c:\program files\AksEdge\kubectl\kubectl.exe' get nodes 63 | Assert-Equal $LastExitCode 0 64 | Write-Host "kubectl output:`n$output" 65 | 66 | $result = $($output -split '\r?\n' -replace '\s+', ';' | ConvertFrom-Csv -Delimiter ';') 67 | 68 | Write-Host "Kubernetes nodes STATUS:" 69 | foreach ( $NODE in $result ) 70 | { 71 | Write-Host "NAME: $($NODE.NAME) STATUS: $($NODE.STATUS)" 72 | } 73 | foreach ( $NODE in $result ) 74 | { 75 | Assert-Equal $NODE.STATUS 'Ready' 76 | } 77 | } 78 | 79 | function E2etest-BasicLinuxNodeOffline-TestOfflineClusterPodsReady 80 | { 81 | param 82 | ( 83 | [String] 84 | # Test Parameter 85 | $JsonTestParameters, 86 | 87 | [HashTable] 88 | # Optional parameters from the commandline 89 | $TestVar 90 | ) 91 | 92 | Write-Host "Running kubectl" 93 | 94 | Get-AksEdgeKubeConfig -Confirm:$false 95 | $kubectloutput = & 'c:\program files\AksEdge\kubectl\kubectl.exe' get pods --all-namespaces 96 | $result = $($kubectloutput -split '\r?\n' -replace '\s+', ';' | ConvertFrom-Csv -Delimiter ';') 97 | Write-Host "`n Kube pods output: $kubectloutput" 98 | 99 | Write-Host "Kubernetes pods STATUS:" 100 | foreach ( $POD in $result ) 101 | { 102 | Write-Host "NAME: $($POD.NAME) READY: $($POD.READY) STATUS: $($POD.STATUS)" 103 | } 104 | 105 | # Verify if we get any pods output from kubectl 106 | $condition = [string]::IsNullOrEmpty($result.NAME) 107 | Assert-Equal $condition $false 108 | 109 | foreach ( $POD in $result ) 110 | { 111 | # Verify if all the pods are Ready 112 | $ReadyValues = $POD.READY.Split("/") 113 | Assert-Equal $ReadyValues[0] $ReadyValues[1] 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure Kubernetes Services (AKS) Edge Essentials 2 | 3 | ## Overview 4 | 5 | This repository is offered for tracking features and issues with the Azure Kubernetes Service (AKS) Edge Essentials. This repository is monitored by the AKS Edge Essentials product team in order to engage with our community and discuss questions, customer scenarios, or feature requests. 6 | 7 | Support through issues on this repository is provided on a **best-effort basis** for issues that are reproducible following our **Bug Guidance** below. To receive urgent support, you must file a support request through official Azure support channels, as urgent support is explicitly out of the scope of this repository's objectives. 8 | 9 | ## Important Links 10 | 11 | | | | 12 | | --------- |- | 13 | | GA Announcement | [https://aka.ms/aks-edge/ga-blog](https://aka.ms/aks-edge/ga-blog) | 14 | | Overview |[https://aka.ms/aks-edge/overview](https://aka.ms/aks-edge/overview) | 15 | | Quickstart |[https://aka.ms/aks-edge/quickstart](https://aka.ms/aks-edge/quickstart) | 16 | | Release Notes| [https://aka.ms/aks-edge/releases](https://aka.ms/aks-edge/releases) | 17 | | PowerShell Reference |[https://aka.ms/aks-edge/reference](https://aka.ms/aks-edge/reference) | 18 | | Azure Arc Jumpstart |[https://aka.ms/AKSEEJumpstart](https://aka.ms/AKSEEJumpstart)| 19 | | Azure Arc Jumpstart Videos| [https://aka.ms/AKSEEVideos](https://aka.ms/AKSEEVideos)| 20 | 21 | ## Bug Guidance 22 | 23 | Bug reports filed on this repository should follow the default issue template that is shown when opening a new issue. At a bare minimum, issues reported on this repository must: 24 | 25 | 1. **Be reproducible outside of the current cluster** 26 | 27 | If you file an issue requiring direct access to your cluster and/or Azure resources, you will be redirected to open an Azure support ticket. Microsoft employees may not ask for personal / subscription information on GitHub. 28 | 29 | 1. **Contain the following information** 30 | 1. **A good title**: Clear, relevant, and descriptive - so that a general idea of the problem can be grasped immediately 31 | 1. **Description**: Before you go into the detail of steps to replicate the issue, you need a brief description. Assume that whoever is reading the report is unfamiliar with the issue/system in question 32 | 1. **Clear, concise steps to replicate the issue outside your specific cluster**.These should let anyone clearly see what you did to see the problem and allow them to recreate it easily. This section should also include results - both expected and actual - along with relevant URLs. 33 | 1. **Be sure to include any supporting information you might have that could aid the developers**. This includes YAML files/deployments, scripts to reproduce, exact commands used, screenshots, etc. 34 | 35 | ## Contributing 36 | 37 | This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to and actually do, grant us 38 | the rights to use your contribution. For details, visit [Microsoft CLA Opensource](https://cla.opensource.microsoft.com). 39 | 40 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 41 | For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 42 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 43 | -------------------------------------------------------------------------------- /tests/E2E/e2e_basiclinuxandwindowsoffline_test.ps1: -------------------------------------------------------------------------------- 1 | 2 | Import-Module "$PSScriptRoot\utils.ps1" 3 | 4 | function Setup-BasicLinuxAndWindowsNodeOffline { 5 | param( 6 | # Test Parameters 7 | [String] 8 | $JsonTestParameters, 9 | 10 | [HashTable] 11 | # Optional parameters from the commandline 12 | $TestVar 13 | ) 14 | 15 | # Get Aide UserConfig 16 | 17 | $retval = Start-AideWorkflow -jsonString $JsonTestParameters 18 | 19 | if($retval) { 20 | Write-Host "Deployment Successful" 21 | } else { 22 | throw "Deployment Failed" 23 | } 24 | } 25 | 26 | function Cleanup-BasicLinuxAndWindowsNodeOffline { 27 | param( 28 | # Test Parameters 29 | [String] 30 | $JsonTestParameters, 31 | 32 | [HashTable] 33 | # Optional parameters from the commandline 34 | $TestVar 35 | ) 36 | 37 | $retval = Remove-AideDeployment 38 | 39 | if($retval) { 40 | Write-Host "Cleanup Successful" 41 | } else { 42 | throw "Cleanup Failed" 43 | } 44 | } 45 | 46 | function E2etest-BasicLinuxAndWindowsNodeOffline-TestOfflineClusterNodesReady { 47 | param( 48 | 49 | # Test Parameters 50 | [String] 51 | $JsonTestParameters, 52 | 53 | [HashTable] 54 | # Optional parameters from the commandline 55 | $TestVar 56 | ) 57 | 58 | Write-Host "Running kubectl on node" 59 | 60 | # Assuming the cluster is ready after this is done, let's prove whether it's good or not 61 | Get-AksEdgeKubeConfig -Confirm:$false 62 | 63 | $output = & 'c:\program files\AksEdge\kubectl\kubectl.exe' get nodes 64 | Assert-Equal $LastExitCode 0 65 | Write-Host "kubectl output:`n$output" 66 | 67 | $result = $($output -split '\r?\n' -replace '\s+', ';' | ConvertFrom-Csv -Delimiter ';') 68 | 69 | Write-Host "Kubernetes nodes STATUS:" 70 | foreach ( $NODE in $result ) 71 | { 72 | Write-Host "NAME: $($NODE.NAME) STATUS: $($NODE.STATUS)" 73 | } 74 | foreach ( $NODE in $result ) 75 | { 76 | Assert-Equal $NODE.STATUS 'Ready' 77 | } 78 | } 79 | 80 | function E2etest-BasicLinuxAndWindowsNodeOffline-TestOfflineClusterPodsReady 81 | { 82 | param 83 | ( 84 | [String] 85 | # Test Parameter 86 | $JsonTestParameters, 87 | 88 | [HashTable] 89 | # Optional parameters from the commandline 90 | $TestVar 91 | ) 92 | 93 | Write-Host "Running kubectl" 94 | 95 | Get-AksEdgeKubeConfig -Confirm:$false 96 | $kubectloutput = & 'c:\program files\AksEdge\kubectl\kubectl.exe' get pods --all-namespaces 97 | $result = $($kubectloutput -split '\r?\n' -replace '\s+', ';' | ConvertFrom-Csv -Delimiter ';') 98 | Write-Host "`n Kube pods output: $kubectloutput" 99 | 100 | Write-Host "Kubernetes pods STATUS:" 101 | foreach ( $POD in $result ) 102 | { 103 | Write-Host "NAME: $($POD.NAME) READY: $($POD.READY) STATUS: $($POD.STATUS)" 104 | } 105 | 106 | # Verify if we get any pods output from kubectl 107 | $condition = [string]::IsNullOrEmpty($result.NAME) 108 | Assert-Equal $condition $false 109 | 110 | foreach ( $POD in $result ) 111 | { 112 | # Verify if all the pods are Ready 113 | $ReadyValues = $POD.READY.Split("/") 114 | Assert-Equal $ReadyValues[0] $ReadyValues[1] 115 | } 116 | } 117 | 118 | function E2eTest-BasicLinuxAndWindowsNodeOffline-WindowsVmIp4Address 119 | { 120 | param 121 | ( 122 | [String] 123 | # Test Parameter 124 | $JsonTestParameters, 125 | 126 | [HashTable] 127 | # Optional parameters from the commandline 128 | $TestVar 129 | ) 130 | $windowsVmIp = Get-WindowsVmIpAddress 131 | 132 | $output = Invoke-WindowsSSH "powershell.exe -command `"(Get-NetIPAddress).IpAddress`"" 133 | $result = $output.Contains($windowsVmIp) 134 | Assert-Equal $result $True 135 | Write-Host "VM IPV4 ip address is: `n$windowsVmIp" 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /samples/storage/local-path-provisioner/local-path-storage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: local-path-provisioner-service-account 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRole 9 | metadata: 10 | name: local-path-provisioner-role 11 | rules: 12 | - apiGroups: [""] 13 | resources: ["nodes", "persistentvolumeclaims", "configmaps"] 14 | verbs: ["get", "list", "watch"] 15 | - apiGroups: [""] 16 | resources: ["endpoints", "persistentvolumes", "pods"] 17 | verbs: ["*"] 18 | - apiGroups: [""] 19 | resources: ["events"] 20 | verbs: ["create", "patch"] 21 | - apiGroups: ["storage.k8s.io"] 22 | resources: ["storageclasses"] 23 | verbs: ["get", "list", "watch"] 24 | --- 25 | apiVersion: rbac.authorization.k8s.io/v1 26 | kind: ClusterRoleBinding 27 | metadata: 28 | name: local-path-provisioner-bind 29 | roleRef: 30 | apiGroup: rbac.authorization.k8s.io 31 | kind: ClusterRole 32 | name: local-path-provisioner-role 33 | subjects: 34 | - kind: ServiceAccount 35 | name: local-path-provisioner-service-account 36 | namespace: kube-system 37 | --- 38 | apiVersion: apps/v1 39 | kind: Deployment 40 | metadata: 41 | name: local-path-provisioner 42 | namespace: kube-system 43 | spec: 44 | replicas: 1 45 | selector: 46 | matchLabels: 47 | app: local-path-provisioner 48 | template: 49 | metadata: 50 | labels: 51 | app: local-path-provisioner 52 | spec: 53 | priorityClassName: "system-node-critical" 54 | serviceAccountName: local-path-provisioner-service-account 55 | tolerations: 56 | - key: "CriticalAddonsOnly" 57 | operator: "Exists" 58 | - key: "node-role.kubernetes.io/control-plane" 59 | operator: "Exists" 60 | effect: "NoSchedule" 61 | - key: "node-role.kubernetes.io/master" 62 | operator: "Exists" 63 | effect: "NoSchedule" 64 | nodeSelector: 65 | "kubernetes.io/os": linux 66 | containers: 67 | - name: local-path-provisioner 68 | image: rancher/local-path-provisioner:master-head 69 | imagePullPolicy: IfNotPresent 70 | command: 71 | - local-path-provisioner 72 | - start 73 | - --config 74 | - /etc/config/config.json 75 | volumeMounts: 76 | - name: config-volume 77 | mountPath: /etc/config/ 78 | env: 79 | - name: POD_NAMESPACE 80 | valueFrom: 81 | fieldRef: 82 | fieldPath: metadata.namespace 83 | volumes: 84 | - name: config-volume 85 | configMap: 86 | name: local-path-config 87 | --- 88 | apiVersion: storage.k8s.io/v1 89 | kind: StorageClass 90 | metadata: 91 | name: local-path 92 | annotations: 93 | storageclass.kubernetes.io/is-default-class: "true" 94 | provisioner: rancher.io/local-path 95 | volumeBindingMode: WaitForFirstConsumer 96 | reclaimPolicy: Delete 97 | --- 98 | kind: ConfigMap 99 | apiVersion: v1 100 | metadata: 101 | name: local-path-config 102 | namespace: kube-system 103 | data: 104 | config.json: |- 105 | { 106 | "nodePathMap":[ 107 | { 108 | "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES", 109 | "paths":["/var/lib/rancher/k3s/storage"] 110 | } 111 | ] 112 | } 113 | setup: |- 114 | #!/bin/sh 115 | while getopts "m:s:p:" opt 116 | do 117 | case $opt in 118 | p) 119 | absolutePath=$OPTARG 120 | ;; 121 | s) 122 | sizeInBytes=$OPTARG 123 | ;; 124 | m) 125 | volMode=$OPTARG 126 | ;; 127 | esac 128 | done 129 | mkdir -m 0777 -p ${absolutePath} 130 | chmod 701 ${absolutePath}/.. 131 | teardown: |- 132 | #!/bin/sh 133 | while getopts "m:s:p:" opt 134 | do 135 | case $opt in 136 | p) 137 | absolutePath=$OPTARG 138 | ;; 139 | s) 140 | sizeInBytes=$OPTARG 141 | ;; 142 | m) 143 | volMode=$OPTARG 144 | ;; 145 | esac 146 | done 147 | rm -rf ${absolutePath} 148 | helperPod.yaml: |- 149 | apiVersion: v1 150 | kind: Pod 151 | metadata: 152 | name: helper-pod 153 | spec: 154 | containers: 155 | - name: helper-pod 156 | image: busybox -------------------------------------------------------------------------------- /tools/scripts/AksEdgeAzureSetup/InstallArcForServer.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Script to install and connect Arc for Server based on json input file 3 | #> 4 | Param( 5 | [String]$jsonFile 6 | ) 7 | 8 | #Requires -RunAsAdministrator 9 | New-Variable -Option Constant -ErrorAction SilentlyContinue -Name azcmagentexe -Value "$env:ProgramW6432\AzureConnectedMachineAgent\azcmagent.exe" 10 | 11 | function Install-AideArcServer { 12 | if (Test-Path -Path $azcmagentexe -PathType Leaf) { 13 | Write-Host "> ConnectedMachineAgent is already installed" -ForegroundColor Green 14 | & $azcmagentexe version 15 | return 16 | } 17 | Write-Host "> Installing ConnectedMachineAgent..." 18 | 19 | $tempPath = Join-Path $env:SystemRoot "AkseeTemp" 20 | if (-Not (Test-Path -Path $tempPath)) { 21 | New-Item -Path $tempPath -ItemType Directory 22 | Write-Output "Directory '$tempPath' created." 23 | } 24 | 25 | Push-Location $tempPath 26 | # Download the installation package 27 | Invoke-WebRequest -Uri "https://aka.ms/azcmagent-windows" -TimeoutSec 30 -OutFile ".\install_windows_azcmagent.ps1" -UseBasicParsing 28 | # Install the hybrid agent 29 | & ".\install_windows_azcmagent.ps1" 30 | if ($LASTEXITCODE -ne 0) { 31 | Write-Host "Error: Failed to install the ConnectedMachineAgent agent : $LASTEXITCODE" -ForegroundColor Red 32 | } else { 33 | Write-Host "Setting up auto update via Microsoft Update" 34 | $ServiceManager = (New-Object -com "Microsoft.Update.ServiceManager") 35 | $ServiceID = "7971f918-a847-4430-9279-4a52d1efe18d" 36 | $ServiceManager.AddService2($ServiceId, 7, "") | Out-Null 37 | } 38 | Remove-Item .\AzureConnectedMachineAgent.msi 39 | Pop-Location 40 | } 41 | 42 | function Get-AideArcServerInfo { 43 | $vmInfo = @{} 44 | $apiVersion = "2020-06-01" 45 | $InstanceUri = $env:IMDS_ENDPOINT + "/metadata/instance?api-version=$apiVersion" 46 | $Proxy = New-Object System.Net.WebProxy 47 | $WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession 48 | $WebSession.Proxy = $Proxy 49 | $response = (Invoke-RestMethod -Headers @{"Metadata" = "true"} -Method GET -Uri $InstanceUri -WebSession $WebSession) 50 | $vmInfo.Add("Name", $response.compute.name) 51 | $vmInfo.Add("ResourceGroupName", $response.compute.resourceGroupName) 52 | $vmInfo.Add("SubscriptionId", $response.compute.subscriptionId) 53 | $vmInfo.Add("Location", $response.compute.location) 54 | return $vmInfo 55 | } 56 | 57 | ### 58 | # Main 59 | ### 60 | if (-not $jsonFile) { 61 | $jsonFile = "$PSScriptRoot\AzureConfig.json" 62 | } 63 | if (-not(Test-Path -Path "$jsonFile" -PathType Leaf)) { 64 | Write-Host "Error: Incorrect input. Enter valid jsonFile path" -ForegroundColor Red 65 | exit -1 66 | } 67 | Write-Verbose "Loading $jsonFile.." 68 | $jsonContent = Get-Content "$jsonFile" | ConvertFrom-Json 69 | 70 | if ($jsonContent.Azure) { 71 | $aicfg = $jsonContent.Azure 72 | } elseif ($jsonContent.SubscriptionId) { 73 | $aicfg = $jsonContent 74 | } else { 75 | Write-Host "Error: Incorrect json content" -ForegroundColor Red 76 | exit -1 77 | } 78 | Write-Host "$aicfg" 79 | if (!(Test-Path -Path $azcmagentexe -PathType Leaf)) { 80 | Write-Host "ConnectedMachineAgent is not installed. Installing now.." -ForegroundColor Gray 81 | Install-AideArcServer 82 | } 83 | $agentstatus = (& $azcmagentexe show) 84 | if (!($($agentstatus | Select-String -Pattern 'Agent Status') -like '*Disconnected')) { 85 | Write-Host "ConnectedMachineAgent is connected." -ForegroundColor Green 86 | Get-AideArcServerInfo 87 | exit 0 88 | } 89 | Write-Host "ConnectedMachineAgent is disconnected." -ForegroundColor Yellow 90 | Write-Host "Connecting now" 91 | $connectargs = @( "--resource-group", "$($aicfg.ResourceGroupName)", 92 | "--tenant-id", "$($aicfg.TenantId)", 93 | "--location", "$($aicfg.Location)", 94 | "--subscription-id", "$($aicfg.SubscriptionId)", 95 | "--tags", "owner=AksEdge" 96 | "--cloud", "AzureCloud", 97 | "--service-principal-id", "$($aicfg.Auth.ServicePrincipalId)", 98 | "--service-principal-secret", "$($aicfg.Auth.Password)" 99 | ) 100 | $hostSettings = Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' | Select-Object ProxyServer, ProxyEnable 101 | if ($hostSettings.ProxyEnable) { 102 | & $azcmagentexe config set proxy.url $($hostSettings.ProxyServer) 103 | } 104 | & $azcmagentexe connect @connectargs 105 | if ($LastExitCode -eq 0) { 106 | Write-Host "ConnectedMachineAgent connected." -ForegroundColor Green 107 | Get-AideArcServerInfo 108 | } else { 109 | Write-Host "Error in connecting to Azure: $LastExitCode" -ForegroundColor Red 110 | } 111 | exit 0 -------------------------------------------------------------------------------- /.pipeline/templates/e2e-linuxoffline.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: aidescript_e2e_test_linuxoffline 3 | dependsOn: 4 | - mtrxgenerator 5 | displayName: Run E2E Linux Offline Test Suite 6 | pool: 1es-aksiot-windows-x64-ltsc-2021-test-pool 7 | timeoutInMinutes: 60 8 | condition: eq(dependencies.mtrxgenerator.outputs['mtrx.LinuxNodeOffline'], 'true') 9 | 10 | 11 | steps: 12 | - checkout: AksEdge 13 | path: self 14 | clean: true 15 | fetchDepth: 1 16 | 17 | - powershell: | 18 | $CheckInstaller = Get-WmiObject -Class Win32_Product | where Name -match "AKS Edge Essentials - (K8s|K3s)" 19 | $Module = Get-Module -ListAvailable -Name AksEdge 20 | if ($CheckInstaller -ne $Null -Or $Module -ne $Null) 21 | { 22 | Write-Error "AksEdge is already installed on this agent" 23 | Exit 1 24 | } 25 | Write-Host "AksEdge is not installed on this agent" 26 | 27 | $freememInMB = ((Get-CimInstance -Class Win32_OperatingSystem).FreePhysicalMemory / 1024) 28 | $freememInMBRounded = [Math]::Round($freememInMB) 29 | if ($freememInMbRounded -lt 4096) 30 | { 31 | Write-Error "The host does not have enough resources to install and run AksEdge" 32 | Exit 1 33 | } 34 | Write-Host "The host has $freememInMBRounded free memory, AksEdge can be installed on it" 35 | 36 | $PSConfiguration = Get-ExecutionPolicy 37 | if ($PSConfiguration -ne "Bypass" -and $PSConfiguration -ne "Unrestricted") 38 | { 39 | Write-Error "The host current powershell configuration is $PSConfiguration, expected configuration is Bypass or Unrestricted" 40 | Exit 1 41 | } 42 | Write-Host "The host current powershell configuration is $PSConfiguration" 43 | 44 | $SSHCheck = (Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Client*').State 45 | $HyperVHyperVisor = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Hypervisor -Online).State 46 | $HyperV = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online).State 47 | $HyperVMngPowershell = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Management-PowerShell -Online).State 48 | if ($SSHCheck -ne "Installed" -Or $HyperVHyperVisor -ne "Enabled" -Or $HyperV -ne "Enabled" -Or $HyperVMngPowershell -ne "Enabled") 49 | { 50 | Write-Error "Not all software modules are installed, the software modules that are needed are: OpenSSH.Client, Microsoft-Hyper-V-Hypervisor, Microsoft-Hyper-V, Microsoft-Hyper-V-Management-PowerShell." 51 | Exit 1 52 | } 53 | Write-Host "All the software modules are installed: OpenSSH.Client, Microsoft-Hyper-V-Hypervisor, Microsoft-Hyper-V, Microsoft-Hyper-V-Management-PowerShell." 54 | displayName: 'Validating agent state' 55 | 56 | - powershell: | 57 | Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force 58 | $modules = Get-Module -ListAvailable 59 | Write-Host "Modules available are" 60 | Write-Host $modules 61 | $psgallery = Get-PSRepository | Where-Object { $_.Name -like "PSGallery" } 62 | if ($psgallery.InstallationPolicy -ine "Trusted") { 63 | # Do this always as by default PSGallery is untrusted. 64 | # See alternate means to force install rather than making this trusted. 65 | Write-Host "Setting PSGallery as Trusted Source" 66 | Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted 67 | } 68 | else { Write-Host "PSGallery is trusted" -ForegroundColor Green } 69 | displayName: 'Enabling PS Reposiotory access to install required module' 70 | 71 | - powershell: | 72 | $LogFile = 'e2e_junit.xml' 73 | $TestPath = "$(Agent.BuildDirectory)\self\tests" 74 | 75 | $JsonConfigFilePath = "$(Agent.BuildDirectory)\self\tools\aide-userconfig.json" 76 | $JsonTestParameters = Get-Content -Raw $JsonConfigFilePath | ConvertFrom-Json 77 | $JsonTestParameters.AksEdgeConfigFile = "$(Agent.BuildDirectory)\self\tools\aksedge-config.json" 78 | 79 | $JsonTestParameters | ConvertTo-Json | Out-File $JsonConfigFilePath 80 | 81 | Write-Host "Executing tests from $TestPath, Results at $LogFile" 82 | Get-ChildItem -Path $TestPath 83 | & c:\windows\system32\windowspowershell\v1.0\powershell.exe -File "$TestPath\e2e.ps1" -LogFile $LogFile -JsonConfigFilePath $JsonConfigFilePath -IncludeGroup BasicLinuxNodeOffline 84 | Copy-Item -Path $LogFile -Destination "$(Build.ArtifactStagingDirectory)\e2e_junit.xml" 85 | Copy-Item -Path $TestPath\Logs-*.zip -Destination "$(Build.ArtifactStagingDirectory)\$E2E-Logs.zip" 86 | displayName: 'Run e2e.ps1' 87 | 88 | - task: PublishTestResults@2 89 | inputs: 90 | testResultsFormat: JUnit 91 | testResultsFiles: '$(Build.ArtifactStagingDirectory)/e2e_junit.xml' 92 | testRunTitle: 'AideScripts E2E Test Pass' 93 | displayName: 'Publish E2E Test Results' -------------------------------------------------------------------------------- /tools/scripts/AksEdgeQuickStart/README.md: -------------------------------------------------------------------------------- 1 | # AksEdge Quick Start 2 | 3 | AksEdgeQuickStart enables you to quickly bootstrap your machine with installation and deployment of AKS Edge Essentials, setup your Azure portal with the required configurations and use the credentials created in the setup to connect your machine to Arc for Servers and the cluster to Arc for Connected Kubernetes. 4 | 5 | ## Prerequisites 6 | 7 | - See the [Microsoft Software License Terms](https://learn.microsoft.com/azure/aks/hybrid/aks-edge-software-license-terms) as they apply to your use of the software. By using the AksEdgeQuickStart script, you accept the Microsoft Software License Terms and the `AcceptEULA` flag is set to `true` indicating acceptance 8 | - Check your machine for this default system requirements 9 | - Free Memory : 4.5GB (as the Linux VM is configured for 4GB) 10 | - Free Storage : 20GB 11 | - vCPUs Available : 4 vCPUs 12 | - The above are defined in the json file as defaults. You can change them to your desired values. See [System requirements](https://learn.microsoft.com/azure/aks/hybrid/aks-edge-system-requirements) for the minimum requirements. 13 | 14 | - Get the following information ready: 15 | - Your Subscription ID ``: In the Azure portal, select the subscription you're using and look for the subscription ID (GUID) 16 | - Your Tenant ID ``: In the Azure portal, search Azure Active Directory, which should take you to the Default Directory page. Look for the tenant ID (GUID). 17 | - The Location (Azure region) ``: where you want your resources to be created, see [Azure Arc by Region](https://azure.microsoft.com/explore/global-infrastructure/products-by-region/?products=azure-arc) for the Locations supported by `Azure Arc enabled servers` and `Azure Arc enabled Kubernetes` services. Choose a region where both are supported. 18 | 19 | ## Run the script 20 | 21 | - Open an elevated powershell prompt and change directory to your working folder. 22 | - Download the `AksEdgeQuickStart.ps1` script. Depending on the policy setup on your machine, you may require to unblock the file before running. 23 | 24 | ```powershell 25 | $url = "https://raw.githubusercontent.com/Azure/AKS-Edge/main/tools/scripts/AksEdgeQuickStart/AksEdgeQuickStart.ps1" 26 | Invoke-WebRequest -Uri $url -OutFile .\AksEdgeQuickStart.ps1 -UseBasicParsing 27 | Unblock-File .\AksEdgeQuickStart.ps1 28 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force 29 | ``` 30 | 31 | - Run the script with required parameters 32 | 33 | ```powershell 34 | .\AksEdgeQuickStart.ps1 -SubscriptionId "" -TenantId "" -Location "" 35 | ``` 36 | 37 | For installing the K8s version, use 38 | 39 | ```powershell 40 | .\AksEdgeQuickStart.ps1 -SubscriptionId "" -TenantId "" -Location "" -UseK8s 41 | ``` 42 | 43 | By default, the main branch of the Azure/AKS-Edge repo is used. However, if you need to specify a specific release tag, you can do so 44 | 45 | ```powershell 46 | .\AksEdgeQuickStart.ps1 -SubscriptionId "" -TenantId "" -Location "" -Tag "1.0.406.0" 47 | ``` 48 | 49 | Alternate format of invocation 50 | 51 | ```powershell 52 | $parameters = @{ 53 | SubscriptionId = "" 54 | TenantId = "" 55 | Location = "" 56 | UseK8s = $false 57 | Tag = "" 58 | } 59 | .\AksEdgeQuickStart.ps1 @parameters 60 | ``` 61 | 62 | ## What does this script do? 63 | 64 | 1. In the working folder, the script downloads the Github archive [Azure/AKS-Edge](https://github.com/Azure/AKS-Edge) and unzips to a folder `AKS-Edge-main` (or `AKS-Edge-`). By default this downloads the current main branch. 65 | 2. Populates the aide-userconfig.json and aksedge-config.json with the contents present in the script.( `herestrings $aideuserConfig and $aksedgeConfig` ) and invokes the `AksEdgeShell` prompt. 66 | 3. Invokes `AksEdgeAzureSetup.ps1` script to configure the Azure subscription and create the required service principal. See [AksEdgeAzureSetup](../AksEdgeAzureSetup/README.md) for more details on the Azure setup. 67 | 68 | ```powershell 69 | .\AksEdgeAzureSetup.ps1 -jsonFile $aidejson -spContributorRole -spCredReset 70 | ``` 71 | 72 | - Note that this will prompt for an interactive login session to create the required resource group(`aksedge-rg`), service principal account (`aksedge-sp`) in the azure subscription. 73 | 74 | 4. Downloads the AKS Edge Essentials MSI, installs it and deploys `SingleMachineCluster` using the `Start-AideWorkflow` function. 75 | - This function invokes `Install-AksEdgeHostFeatures` that installs all the required OS features and policy settings on the host machine. A restart will be triggered when the Hyper-V feature is enabled and when this occurs, the script needs to be re-run to continue further. 76 | 5. Finally, using the Azure credentials created in step 2, the host machine and the cluster are connected to Arc using `Connect-AideArc` function. 77 | - Note that the required Az Powershell modules are installed using `Initialise-AideArc` function. 78 | -------------------------------------------------------------------------------- /samples/others/metrics-server.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | k8s-app: metrics-server 6 | name: metrics-server 7 | namespace: kube-system 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | k8s-app: metrics-server 14 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 15 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 16 | rbac.authorization.k8s.io/aggregate-to-view: "true" 17 | name: system:aggregated-metrics-reader 18 | rules: 19 | - apiGroups: 20 | - metrics.k8s.io 21 | resources: 22 | - pods 23 | - nodes 24 | verbs: 25 | - get 26 | - list 27 | - watch 28 | --- 29 | apiVersion: rbac.authorization.k8s.io/v1 30 | kind: ClusterRole 31 | metadata: 32 | labels: 33 | k8s-app: metrics-server 34 | name: system:metrics-server 35 | rules: 36 | - apiGroups: 37 | - "" 38 | resources: 39 | - nodes/metrics 40 | verbs: 41 | - get 42 | - apiGroups: 43 | - "" 44 | resources: 45 | - pods 46 | - nodes 47 | verbs: 48 | - get 49 | - list 50 | - watch 51 | --- 52 | apiVersion: rbac.authorization.k8s.io/v1 53 | kind: RoleBinding 54 | metadata: 55 | labels: 56 | k8s-app: metrics-server 57 | name: metrics-server-auth-reader 58 | namespace: kube-system 59 | roleRef: 60 | apiGroup: rbac.authorization.k8s.io 61 | kind: Role 62 | name: extension-apiserver-authentication-reader 63 | subjects: 64 | - kind: ServiceAccount 65 | name: metrics-server 66 | namespace: kube-system 67 | --- 68 | apiVersion: rbac.authorization.k8s.io/v1 69 | kind: ClusterRoleBinding 70 | metadata: 71 | labels: 72 | k8s-app: metrics-server 73 | name: metrics-server:system:auth-delegator 74 | roleRef: 75 | apiGroup: rbac.authorization.k8s.io 76 | kind: ClusterRole 77 | name: system:auth-delegator 78 | subjects: 79 | - kind: ServiceAccount 80 | name: metrics-server 81 | namespace: kube-system 82 | --- 83 | apiVersion: rbac.authorization.k8s.io/v1 84 | kind: ClusterRoleBinding 85 | metadata: 86 | labels: 87 | k8s-app: metrics-server 88 | name: system:metrics-server 89 | roleRef: 90 | apiGroup: rbac.authorization.k8s.io 91 | kind: ClusterRole 92 | name: system:metrics-server 93 | subjects: 94 | - kind: ServiceAccount 95 | name: metrics-server 96 | namespace: kube-system 97 | --- 98 | apiVersion: v1 99 | kind: Service 100 | metadata: 101 | labels: 102 | k8s-app: metrics-server 103 | name: metrics-server 104 | namespace: kube-system 105 | spec: 106 | ports: 107 | - name: https 108 | port: 443 109 | protocol: TCP 110 | targetPort: https 111 | selector: 112 | k8s-app: metrics-server 113 | --- 114 | apiVersion: apps/v1 115 | kind: Deployment 116 | metadata: 117 | labels: 118 | k8s-app: metrics-server 119 | name: metrics-server 120 | namespace: kube-system 121 | spec: 122 | selector: 123 | matchLabels: 124 | k8s-app: metrics-server 125 | strategy: 126 | rollingUpdate: 127 | maxUnavailable: 0 128 | template: 129 | metadata: 130 | labels: 131 | k8s-app: metrics-server 132 | spec: 133 | containers: 134 | - args: 135 | - --cert-dir=/tmp 136 | - --secure-port=4443 137 | - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname 138 | - --kubelet-use-node-status-port 139 | - --metric-resolution=15s 140 | - --kubelet-insecure-tls 141 | - --kubelet-preferred-address-types=InternalIP 142 | image: k8s.gcr.io/metrics-server/metrics-server:v0.6.1 143 | imagePullPolicy: IfNotPresent 144 | livenessProbe: 145 | failureThreshold: 3 146 | httpGet: 147 | path: /livez 148 | port: https 149 | scheme: HTTPS 150 | periodSeconds: 10 151 | name: metrics-server 152 | ports: 153 | - containerPort: 4443 154 | name: https 155 | protocol: TCP 156 | readinessProbe: 157 | failureThreshold: 3 158 | httpGet: 159 | path: /readyz 160 | port: https 161 | scheme: HTTPS 162 | initialDelaySeconds: 20 163 | periodSeconds: 10 164 | resources: 165 | requests: 166 | cpu: 100m 167 | memory: 200Mi 168 | securityContext: 169 | allowPrivilegeEscalation: false 170 | readOnlyRootFilesystem: true 171 | runAsNonRoot: true 172 | runAsUser: 1000 173 | volumeMounts: 174 | - mountPath: /tmp 175 | name: tmp-dir 176 | nodeSelector: 177 | kubernetes.io/os: linux 178 | priorityClassName: system-cluster-critical 179 | serviceAccountName: metrics-server 180 | volumes: 181 | - emptyDir: {} 182 | name: tmp-dir 183 | --- 184 | apiVersion: apiregistration.k8s.io/v1 185 | kind: APIService 186 | metadata: 187 | labels: 188 | k8s-app: metrics-server 189 | name: v1beta1.metrics.k8s.io 190 | spec: 191 | group: metrics.k8s.io 192 | groupPriorityMinimum: 100 193 | insecureSkipTLSVerify: true 194 | service: 195 | name: metrics-server 196 | namespace: kube-system 197 | version: v1beta1 198 | versionPriority: 100 199 | -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/aksedge-dc.puml: -------------------------------------------------------------------------------- 1 | @startjson AksEdgeSchema 2 | 22 | #highlight "SchemaVersion" 23 | { 24 | "SchemaVersion": "1.15", 25 | "Version": "1.0", 26 | "DeploymentType": [ 27 | "SingleMachineCluster", 28 | "ScalableCluster", 29 | "CapiCluster(Reserved)" 30 | ], 31 | "Init": { 32 | "ServiceIPRangeStart": "ipv4", 33 | "ServiceIPRangeSize": { 34 | "type": "integer", 35 | "minimum" : 1, 36 | "maximum" : 127 37 | }, 38 | "KmsPlugin": { 39 | "Enable": false 40 | } 41 | }, 42 | "Join":"Reserved", 43 | "Arc": { 44 | "ClusterName": "string", 45 | "Location": "string", 46 | "ResourceGroupName": "string", 47 | "SubscriptionId": "GUID", 48 | "TenantId": "GUID", 49 | "ClientId": "string", 50 | "ClientSecret": "string", 51 | "CustomLocationsOid": "string", 52 | "EnableWorkloadIdentity": "boolean" 53 | }, 54 | "User": { 55 | "AcceptEula": true, 56 | "AcceptOptionalTelemetry": true, 57 | "VolumeLicense":{ 58 | "EnrollmentId":"string", 59 | "PartNumber":"string" 60 | }, 61 | "AcceptGpuWarning": false 62 | }, 63 | "Network": { 64 | "ControlPlaneEndpointIp": "ipv4", 65 | "NetworkPlugin": [ 66 | "calico", 67 | "flannel" 68 | ], 69 | "Ip4GatewayAddress": "ipv4", 70 | "Ip4PrefixLength": { 71 | "type": "integer", 72 | "default": 24, 73 | "minimum": 1, 74 | "maximum": 31 75 | }, 76 | "Ip4AddressPrefix":"string", 77 | "DnsServers": [["ipv4"]], 78 | "InternetDisabled": false, 79 | "SkipAddressFreeCheck":false, 80 | "SkipDnsCheck":false, 81 | "Proxy": { 82 | "Http":"string", 83 | "Https":"string", 84 | "No":"string" 85 | } 86 | }, 87 | "Machines":[{ 88 | "ArcHybridComputeMachineId":"Reserved", 89 | "NetworkConnection":{ 90 | "AdapterName":"string", 91 | "Mtu":"integer" 92 | }, 93 | "LinuxNode":{ 94 | "CpuCount": { 95 | "type": "integer", 96 | "default": 4, 97 | "minimum": 2 98 | }, 99 | "MemoryInMB": { 100 | "type": "integer", 101 | "default": 4096, 102 | "multipleOf": 2, 103 | "minimum": 2048 104 | }, 105 | "MemoryHugePages": { 106 | "Size": { 107 | "type": "enum", 108 | "default": 2048, 109 | "values": [2048,1048576] 110 | }, 111 | "count": { 112 | "type": "integer", 113 | "default": 0 114 | } 115 | }, 116 | "DataSizeInGB": { 117 | "type": "integer", 118 | "default": 10 119 | }, 120 | "LogSizeInGB": { 121 | "type": "integer", 122 | "default": 1, 123 | "minimum" : 1, 124 | "maximum" : 10 125 | }, 126 | "TimeoutSeconds": { 127 | "type": "int", 128 | "default": 300 129 | }, 130 | "TpmPassthrough": false, 131 | "SecondaryNetworks": [ 132 | { 133 | "VMSwitchName" : "string", 134 | "Ip4Address": "ipv4", 135 | "Ip4GatewayAddress": "ipv4", 136 | "Ip4PrefixLength": "integer" 137 | } 138 | ], 139 | "GpuPassthrough": { 140 | "Name": "string", 141 | "Type": "string", 142 | "Count": "integer" 143 | }, 144 | "Ip4Address": "ipv4", 145 | "MacAddress": "string", 146 | "Mtu": "integer", 147 | "ControlPlane" : false 148 | }, 149 | "WindowsNode":{ 150 | "CpuCount": { 151 | "type": "integer", 152 | "default": 2, 153 | "minimum": 2 154 | }, 155 | "MemoryInMB": { 156 | "type": "integer", 157 | "default": 4096, 158 | "multipleOf": 2, 159 | "minimum": 2048 160 | }, 161 | "TimeoutSeconds": { 162 | "type": "int", 163 | "default": 900 164 | }, 165 | "Ip4Address": "ipv4", 166 | "MacAddress": "string", 167 | "Mtu": "integer" 168 | } 169 | }] 170 | } 171 | @endjson -------------------------------------------------------------------------------- /.pipeline/templates/e2e-linuxandwindows.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: aidescript_e2e_test_linuxandwindows 3 | dependsOn: 4 | - mtrxgenerator 5 | displayName: Run E2E Linux And Windows Offline Test Suite 6 | pool: 1es-aksiot-windows-x64-ltsc-2021-test-pool 7 | timeoutInMinutes: 60 8 | condition: eq(dependencies.mtrxgenerator.outputs['mtrx.LinuxAndWindows'], 'true') 9 | 10 | steps: 11 | - checkout: AksEdge 12 | path: self 13 | clean: true 14 | fetchDepth: 1 15 | 16 | - powershell: | 17 | $CheckInstaller = Get-WmiObject -Class Win32_Product | where Name -match "AKS Edge Essentials - (K8s|K3s)" 18 | $Module = Get-Module -ListAvailable -Name AksEdge 19 | if ($CheckInstaller -ne $Null -Or $Module -ne $Null) 20 | { 21 | Write-Error "AksEdge is already installed on this agent" 22 | Exit 1 23 | } 24 | Write-Host "AksEdge is not installed on this agent" 25 | 26 | $freememInMB = ((Get-CimInstance -Class Win32_OperatingSystem).FreePhysicalMemory / 1024) 27 | $freememInMBRounded = [Math]::Round($freememInMB) 28 | if ($freememInMbRounded -lt 4096) 29 | { 30 | Write-Error "The host does not have enough resources to install and run AksEdge" 31 | Exit 1 32 | } 33 | Write-Host "The host has $freememInMBRounded free memory, AksEdge can be installed on it" 34 | 35 | $PSConfiguration = Get-ExecutionPolicy 36 | if ($PSConfiguration -ne "Bypass" -and $PSConfiguration -ne "Unrestricted") 37 | { 38 | Write-Error "The host current powershell configuration is $PSConfiguration, expected configuration is Bypass or Unrestricted" 39 | Exit 1 40 | } 41 | Write-Host "The host current powershell configuration is $PSConfiguration" 42 | 43 | $SSHCheck = (Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Client*').State 44 | $HyperVHyperVisor = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Hypervisor -Online).State 45 | $HyperV = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online).State 46 | $HyperVMngPowershell = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Management-PowerShell -Online).State 47 | if ($SSHCheck -ne "Installed" -Or $HyperVHyperVisor -ne "Enabled" -Or $HyperV -ne "Enabled" -Or $HyperVMngPowershell -ne "Enabled") 48 | { 49 | Write-Error "Not all software modules are installed, the software modules that are needed are: OpenSSH.Client, Microsoft-Hyper-V-Hypervisor, Microsoft-Hyper-V, Microsoft-Hyper-V-Management-PowerShell." 50 | Exit 1 51 | } 52 | Write-Host "All the software modules are installed: OpenSSH.Client, Microsoft-Hyper-V-Hypervisor, Microsoft-Hyper-V, Microsoft-Hyper-V-Management-PowerShell." 53 | displayName: 'Validating agent state' 54 | 55 | - powershell: | 56 | Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force 57 | $modules = Get-Module -ListAvailable 58 | Write-Host "Modules available are" 59 | Write-Host $modules 60 | $psgallery = Get-PSRepository | Where-Object { $_.Name -like "PSGallery" } 61 | if ($psgallery.InstallationPolicy -ine "Trusted") { 62 | # Do this always as by default PSGallery is untrusted. 63 | # See alternate means to force install rather than making this trusted. 64 | Write-Host "Setting PSGallery as Trusted Source" 65 | Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted 66 | } 67 | else { Write-Host "PSGallery is trusted" -ForegroundColor Green } 68 | displayName: 'Enabling PS Reposiotory access to install required module' 69 | 70 | - powershell: | 71 | $LogFile = 'e2e_junit.xml' 72 | $TestPath = "$(Agent.BuildDirectory)\self\tests" 73 | $WindowsConfig = [PSCustomObject]@{ 74 | "CpuCount"= 4 75 | "MemoryInMB"= 4096 76 | "DataSizeInGB"= 20 77 | } 78 | 79 | $AksEdgeConfigFilePath = "$(Agent.BuildDirectory)\self\tools\aksedge-config.json" 80 | $AksEdgeConfig = Get-Content -Raw $AksEdgeConfigFilePath | ConvertFrom-Json 81 | Add-Member -InputObject $AksEdgeConfig.Machines[0] -MemberType NoteProperty -Name WindowsNode -Value $WindowsConfig 82 | $AksEdgeConfig | ConvertTo-Json | Out-File $AksEdgeConfigFilePath 83 | 84 | $JsonConfigFilePath = "$(Agent.BuildDirectory)\self\tools\aide-userconfig.json" 85 | 86 | $JsonTestParameters = Get-Content -Raw $JsonConfigFilePath | ConvertFrom-Json 87 | $JsonTestParameters.AksEdgeConfigFile = $AksEdgeConfigFilePath 88 | 89 | $JsonTestParameters | ConvertTo-Json -Depth 4 | Out-File $JsonConfigFilePath 90 | 91 | Write-Host "Executing tests from $TestPath, Results at $LogFile" 92 | Get-ChildItem -Path $TestPath 93 | & c:\windows\system32\windowspowershell\v1.0\powershell.exe -File "$TestPath\e2e.ps1" -LogFile $LogFile -JsonConfigFilePath $JsonConfigFilePath -IncludeGroup BasicLinuxAndWindowsNodeOffline 94 | Copy-Item -Path $LogFile -Destination "$(Build.ArtifactStagingDirectory)\e2e_junit.xml" 95 | Copy-Item -Path $TestPath\Logs-*.zip -Destination "$(Build.ArtifactStagingDirectory)\$E2E-Logs.zip" 96 | displayName: 'Run e2e.ps1' 97 | 98 | - task: PublishTestResults@2 99 | inputs: 100 | testResultsFormat: JUnit 101 | testResultsFiles: '$(Build.ArtifactStagingDirectory)/e2e_junit.xml' 102 | testRunTitle: 'AideScripts E2E Test Pass' 103 | displayName: 'Publish E2E Test Results' -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/AksEdgeDeploy.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PSGet_AksEdgeDeploy' 3 | # 4 | # Generated by: Microsoft Corporation 5 | # 6 | # Generated on: 05/12/2022 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'AksEdgeDeploy.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.0.250318.0900' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '4c2636b1-a4ad-4474-8af8-5b820c2149b3' 22 | 23 | # Author of this module 24 | Author = 'Microsoft Corporation' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Microsoft Corporation' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) Microsoft Corporation. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | # Description = '' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | PowerShellVersion = '5.0' 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = 'Get-AideUserConfig', 'Read-AideUserConfig', 'Set-AideUserConfig', 'Test-AideUserConfig', 'Start-AideWorkflow', 'New-AideVmSwitch', 73 | 'Test-AideVmSwitch', 'Remove-AideVmSwitch', 'Invoke-AideDeployment', 'Test-AideDeployment', 'Remove-AideDeployment', 'Test-AideLinuxVmRun', 'Get-AideMsiVersion', 74 | 'Install-AideMsi', 'Test-AideMsiInstall', 'Remove-AideMsi', 'Get-AideHostPcInfo', 'Invoke-AideLinuxVmShell', 'Get-AideLinuxVmFile', 75 | 'Format-AideJson', 'Install-AideArcServer', 'Test-AideArcServer', 'Connect-AideArcServer', 'Disconnect-AideArcServer', 76 | 'Get-AideArcServerInfo', 'Enter-AideArcSession', 'Exit-AideArcSession', 'Initialize-AideArc', 'Test-AideArcKubernetes', 'Connect-AideArcKubernetes', 'Disconnect-AideArcKubernetes', 77 | 'Get-AideArcKubernetesServiceToken', 'Get-AideArcServerSMI', 'Get-AideArcClusterName','Get-AideInfra','Connect-AideArc','Disconnect-AideArc' 78 | 79 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 80 | CmdletsToExport = @() 81 | 82 | # Variables to export from this module 83 | # VariablesToExport = @() 84 | 85 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 86 | AliasesToExport = @('mars') 87 | 88 | # DSC resources to export from this module 89 | # DscResourcesToExport = @() 90 | 91 | # List of all modules packaged with this module 92 | # ModuleList = @() 93 | 94 | # List of all files packaged with this module 95 | # FileList = @() 96 | 97 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 98 | PrivateData = @{ 99 | 100 | PSData = @{ 101 | 102 | # Tags applied to this module. These help with module discovery in online galleries. 103 | # Tags = @() 104 | 105 | # A URL to the license for this module. 106 | # LicenseUri = '' 107 | 108 | # A URL to the main website for this project. 109 | # ProjectUri = '' 110 | 111 | # A URL to an icon representing this module. 112 | # IconUri = '' 113 | 114 | # ReleaseNotes of this module 115 | # ReleaseNotes = '' 116 | 117 | # External dependent modules of this module 118 | # ExternalModuleDependencies = '' 119 | 120 | } # End of PSData hashtable 121 | 122 | } # End of PrivateData hashtable 123 | 124 | # HelpInfo URI of this module 125 | # HelpInfoURI = '' 126 | 127 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 128 | # DefaultCommandPrefix = '' 129 | 130 | } 131 | -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/aide-ucschema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://microsoft.com/aide-userconfig.schema.json", 3 | "$schema": "https://json-schema.org/draft/2020-12/schema", 4 | "title": "AKS edge Remote Deployment Configuration", 5 | "type": "object", 6 | "properties": { 7 | "SchemaVersion": { 8 | "type": "string", 9 | "default": "1.3", 10 | "description": "Version of the schema/format of the json" 11 | }, 12 | "Version": { 13 | "type": "string", 14 | "default": "1.0", 15 | "description": "Version of the json instance" 16 | }, 17 | "AksEdgeProduct": { 18 | "enum": [ 19 | "AKS Edge Essentials - K8s", 20 | "AKS Edge Essentials - K3s" 21 | ], 22 | "description": "Product name" 23 | }, 24 | "AksEdgeProductUrl": { 25 | "type": "string", 26 | "description": "Product URL for download" 27 | }, 28 | "Azure": { 29 | "type": "object", 30 | "properties": { 31 | "ClusterName": { 32 | "type": "string", 33 | "description": "Cluster name to be used when connecting to Azure Arc-enabled Kubernetes" 34 | }, 35 | "Location": { 36 | "type": "string", 37 | "description": "Azure Location for creating the resource group" 38 | }, 39 | "ResourceGroupName": { 40 | "type": "string", 41 | "description": "Resource group name to be used for Azure Arc-enabled Server/Kubernetes" 42 | }, 43 | "SubscriptionId": { 44 | "type": "GUID", 45 | "description": "SubscriptionId to be used for Azure Arc-enabled Server/Kubernetes" 46 | }, 47 | "TenantId": { 48 | "type": "GUID", 49 | "description": "TenantId to be used for Azure Arc-enabled Server/Kubernetes" 50 | }, 51 | "SubscriptionName": { 52 | "type": "string", 53 | "description": "Subscription Name to be used for creating serviceprincipal" 54 | }, 55 | "ServicePrincipalName": { 56 | "type": "string", 57 | "description": "ServicePrincipalName to be used for creating service principal to onboard Arc-enabled Server/Kubernetes" 58 | }, 59 | "CustomLocationOID":{ 60 | "type": "string", 61 | "description": "ObjectID for the custom locations resource provider to be used for creating custom locations " 62 | }, 63 | "Auth": { 64 | "type": "object", 65 | "propertires": { 66 | "ServicePrincipalId": { 67 | "type": "string", 68 | "description": "ServicePrincipalId for ServicePrincipalName to onboard Arc-enabled Server/Kubernetes" 69 | }, 70 | "Password": { 71 | "type": "string", 72 | "description": "Password corresponding to ServicePrincipalId to onboard Arc-enabled Server/Kubernetes" 73 | } 74 | } 75 | }, 76 | "EnableWorkloadIdentity": { 77 | "type": "boolean", 78 | "description": "Enables Workload Identity (only for AIO)" 79 | }, 80 | "EnableKeyManagement": { 81 | "type": "boolean", 82 | "description": "Enables Key management (key rotation) (only for AIO)" 83 | }, 84 | "GatewayResourceId": { 85 | "type": "string", 86 | "description": "Resource Id for the Arc Gateway resource (only for AIO)" 87 | }, 88 | "ConnectedMachineName":{ 89 | "type": "string", 90 | "description": "Connected Machine name used for Azure Arc enabled Server" 91 | } 92 | } 93 | }, 94 | "InstallOptions": { 95 | "type": "object", 96 | "properties": { 97 | "InstallPath": { 98 | "type": "string", 99 | "description": "Path to install AksEdge software" 100 | }, 101 | "VhdxPath": { 102 | "type": "string", 103 | "description": "Path to create/store AksEdge VM Vhdx files" 104 | } 105 | } 106 | }, 107 | "VSwitch": { 108 | "type": "object", 109 | "properties": { 110 | "Name": { 111 | "type": "string", 112 | "description": "Name of the External vSwitch" 113 | }, 114 | "AdapterName": { 115 | "type": "string", 116 | "description": "Name of the Physical Network Adapter" 117 | } 118 | } 119 | }, 120 | "AksEdgeConfigFile": { 121 | "type": "string", 122 | "description": "file path for the AKS Edge Deployment Configuration. If AksEdgeConfig object is defined, it supercedes the specification." 123 | }, 124 | "AksEdgeConfig": { 125 | "type": "object", 126 | "$ref": "file:aksedge-dcschema.json", 127 | "description": "Embedded AKS Edge Deployment Configuration Object." 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /tools/scripts/AksEdgeAzureSetup/AksEdgeAzureSetup-Test.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Sample script to setup Azure subscription for Arc for Kubernetes Connection 3 | #> 4 | Param( 5 | [String]$jsonFile 6 | ) 7 | 8 | #Requires -RunAsAdministrator 9 | New-Variable -Name gAksEdgeAzureSetupTest -Value "1.0.230109.1600" -Option Constant -ErrorAction SilentlyContinue 10 | 11 | function Install-AzCli { 12 | #Check if Az CLI is installed. If not install it. 13 | $AzCommand = Get-Command -Name az -ErrorAction SilentlyContinue 14 | if (!$AzCommand) { 15 | $CLIPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin" 16 | Write-Host "> Installing AzCLI..." 17 | $tempPath = Join-Path $env:SystemRoot "AkseeTemp" 18 | if (-Not (Test-Path -Path $tempPath)) { 19 | New-Item -Path $tempPath -ItemType Directory 20 | Write-Output "Directory '$tempPath' created." 21 | } 22 | 23 | Push-Location $tempPath 24 | $progressPreference = 'silentlyContinue' 25 | Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi -UseBasicParsing 26 | $progressPreference = 'Continue' 27 | Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /passive' 28 | Remove-Item .\AzureCLI.msi 29 | Pop-Location 30 | [System.Environment]::SetEnvironmentVariable("Path", "$($CLIPath);$env:Path") 31 | az config set core.disable_confirm_prompt=yes 32 | az config set core.only_show_errors=yes 33 | #az config set auto-upgrade.enable=yes 34 | } 35 | Write-Host "> Azure CLI installed" -ForegroundColor Green 36 | <# Dont need extensions here. 37 | $extlist = (az extension list --query [].name | ConvertFrom-Json -ErrorAction SilentlyContinue) 38 | $reqExts = @("connectedmachine", "connectedk8s", "customlocation") 39 | foreach ($ext in $reqExts) { 40 | if ($extlist -and $extlist.Contains($ext)) { 41 | Write-Host "> az extension $ext installed" -ForegroundColor Green 42 | } else { 43 | Write-Host "Installing az extension $ext" 44 | az extension add --name $ext 45 | } 46 | } 47 | #> 48 | } 49 | 50 | ### 51 | # Main 52 | ### 53 | Write-Host "gAksEdgeAzureSetupTest version `t: $gAksEdgeAzureSetupTest" 54 | if (($jsonFile) -and -not(Test-Path -Path "$jsonFile" -PathType Leaf)) { 55 | Write-Host "Error: Incorrect input. Enter valid jsonFile path or jsonString" -ForegroundColor Red 56 | exit -1 57 | } 58 | Write-Verbose "Loading $jsonFile.." 59 | $jsonContent = Get-Content "$jsonFile" | ConvertFrom-Json 60 | 61 | if ($jsonContent.Azure) { 62 | $aicfg = $jsonContent.Azure 63 | } elseif ($jsonContent.SubscriptionId) { 64 | $aicfg = $jsonContent 65 | } else { 66 | Write-Host "Error: Incorrect json content" -ForegroundColor Red 67 | exit -1 68 | } 69 | # Install Cli 70 | Install-AzCli 71 | Write-Host "$aicfg" 72 | Write-Host ">> Testing the serviceprincpal access" 73 | $session = (az login --service-principal -u $($aicfg.Auth.ServicePrincipalId) -p $($aicfg.Auth.Password) --tenant $aicfg.TenantId) | ConvertFrom-Json 74 | if (-not $session){ 75 | Write-Host "Error: Auth credentials are invalid" -ForegroundColor Red 76 | exit -1 77 | } 78 | (az account set --subscription $($aicfg.SubscriptionId)) | Out-Null 79 | $session = (az account show | ConvertFrom-Json -ErrorAction SilentlyContinue) 80 | Write-Host "Logged in $($session.name) subscription as $($session.user.name) ($($session.user.type))" 81 | $rgname = $aicfg.ResourceGroupName 82 | $rguri = "/subscriptions/$($aicfg.SubscriptionId)/resourceGroups/$rgname" 83 | $roles = (az role assignment list --all --assignee $($session.user.name)) | ConvertFrom-Json 84 | $onbRoles = @("Azure Connected Machine Onboarding","Kubernetes Cluster - Azure Arc Onboarding") 85 | $rolecnt = 0 86 | if ($roles) { 87 | Write-Host "Roles enabled for this account are:" -ForegroundColor Cyan 88 | foreach ($role in $roles){ 89 | $roledef = $($role.roleDefinitionName) 90 | Write-Host "$roledef for scope $($role.scope)" -ForegroundColor Cyan 91 | if ($($role.scope) -eq $rguri) { 92 | if ($roledef -match 'Owner'){ 93 | $reqRoleFound = $true 94 | } elseif ($onbRoles -contains $roledef) { 95 | $rolecnt +=1 96 | if($rolecnt -eq 2) {$reqRoleFound = $true} 97 | } 98 | } 99 | } 100 | } 101 | if ($reqRoleFound){ 102 | Write-Host "* You have sufficient privileges" -ForegroundColor Green 103 | } else { 104 | Write-Host "x You do not have sufficient privileges for this service principal. Please refer to 'https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-steps#privileged-administrator-roles' for more details." -ForegroundColor Red 105 | } 106 | # Resource group 107 | Write-Host "Checking $rgname..." 108 | $rgexists = az group exists --name $rgname 109 | if ($rgexists -ieq 'true') { 110 | Write-Host "* $rgname exists" -ForegroundColor Green 111 | } else { 112 | Write-Host "$rgname not found" -ForegroundColor Red 113 | } 114 | 115 | # Check and enable namespaces 116 | $namespaces = @("Microsoft.HybridCompute", "Microsoft.GuestConfiguration", "Microsoft.HybridConnectivity", 117 | "Microsoft.Kubernetes", "Microsoft.KubernetesConfiguration", "Microsoft.ExtendedLocation") 118 | foreach ($namespace in $namespaces) { 119 | Write-Host "Checking $namespace..." 120 | $provider = (az provider show -n $namespace | ConvertFrom-Json -ErrorAction SilentlyContinue) 121 | if ($provider.registrationState -ieq "Registered") { 122 | Write-Host "* $namespace provider registered" -ForegroundColor Green 123 | } else { 124 | Write-Host "$namespace provider not registered." -ForegroundColor Red 125 | } 126 | } 127 | Write-Host "Setup test completed." 128 | Write-Host "Logging out." 129 | az logout 130 | exit 0 -------------------------------------------------------------------------------- /.pipeline/templates/e2e-linuxonline.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: aidescript_e2e_test_linuxonline 3 | displayName: Run E2E Linux Online Test Suite 4 | dependsOn: 5 | - mtrxgenerator 6 | pool: 1es-aksiot-windows-x64-ltsc-2021-test-pool 7 | timeoutInMinutes: 60 8 | condition: eq(dependencies.mtrxgenerator.outputs['mtrx.LinuxNodeOnline'], 'true') 9 | 10 | 11 | steps: 12 | - checkout: AksEdge 13 | path: self 14 | clean: true 15 | fetchDepth: 1 16 | 17 | - powershell: | 18 | $CheckInstaller = Get-WmiObject -Class Win32_Product | where Name -match "AKS Edge Essentials - (K8s|K3s)" 19 | $Module = Get-Module -ListAvailable -Name AksEdge 20 | if ($CheckInstaller -ne $Null -Or $Module -ne $Null) 21 | { 22 | Write-Error "AksEdge is already installed on this agent" 23 | Exit 1 24 | } 25 | Write-Host "AksEdge is not installed on this agent" 26 | 27 | $freememInMB = ((Get-CimInstance -Class Win32_OperatingSystem).FreePhysicalMemory / 1024) 28 | $freememInMBRounded = [Math]::Round($freememInMB) 29 | if ($freememInMbRounded -lt 4096) 30 | { 31 | Write-Error "The host does not have enough resources to install and run AksEdge" 32 | Exit 1 33 | } 34 | Write-Host "The host has $freememInMBRounded free memory, AksEdge can be installed on it" 35 | 36 | $PSConfiguration = Get-ExecutionPolicy 37 | if ($PSConfiguration -ne "Bypass" -and $PSConfiguration -ne "Unrestricted") 38 | { 39 | Write-Error "The host current powershell configuration is $PSConfiguration, expected configuration is Bypass or Unrestricted" 40 | Exit 1 41 | } 42 | Write-Host "The host current powershell configuration is $PSConfiguration" 43 | 44 | $SSHCheck = (Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Client*').State 45 | $HyperVHyperVisor = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Hypervisor -Online).State 46 | $HyperV = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online).State 47 | $HyperVMngPowershell = (Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Management-PowerShell -Online).State 48 | if ($SSHCheck -ne "Installed" -Or $HyperVHyperVisor -ne "Enabled" -Or $HyperV -ne "Enabled" -Or $HyperVMngPowershell -ne "Enabled") 49 | { 50 | Write-Error "Not all software modules are installed, the software modules that are needed are: OpenSSH.Client, Microsoft-Hyper-V-Hypervisor, Microsoft-Hyper-V, Microsoft-Hyper-V-Management-PowerShell." 51 | Exit 1 52 | } 53 | Write-Host "All the software modules are installed: OpenSSH.Client, Microsoft-Hyper-V-Hypervisor, Microsoft-Hyper-V, Microsoft-Hyper-V-Management-PowerShell." 54 | displayName: 'Validating agent state' 55 | 56 | - powershell: | 57 | Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force 58 | $modules = Get-Module -ListAvailable 59 | Write-Host "Modules available are" 60 | Write-Host $modules 61 | $psgallery = Get-PSRepository | Where-Object { $_.Name -like "PSGallery" } 62 | if ($psgallery.InstallationPolicy -ine "Trusted") { 63 | # Do this always as by default PSGallery is untrusted. 64 | # See alternate means to force install rather than making this trusted. 65 | Write-Host "Setting PSGallery as Trusted Source" 66 | Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted 67 | } 68 | else { Write-Host "PSGallery is trusted" -ForegroundColor Green } 69 | displayName: 'Enabling PS Reposiotory access to install required module' 70 | 71 | - powershell: | 72 | $LogFile = 'e2e_junit.xml' 73 | $TestPath = "$(Agent.BuildDirectory)\self\tests" 74 | cd $TestPath 75 | $AzureConfig = @{ 76 | 'SubscriptionName' = 'AKS-Edge Essentials Test' 77 | 'SubscriptionId' = 'f9cb372a-8903-4370-9ce0-3042e3bb2cc8' 78 | 'TenantId' = '72f988bf-86f1-41af-91ab-2d7cd011db47' 79 | 'ResourceGroupName' = 'aide-script-testing' 80 | 'ServicePrincipalName' = 'aide-script-testing-sp' 81 | 'Location' = 'EastUS' 82 | 'Auth' = @{ 83 | 'Password' = "$(Password)" 84 | 'ServicePrincipalId' = "$(ServicePrincipalId)" 85 | } 86 | 'CustomLocationOID' = '51dfe1e8-70c6-4de5-a08e-e18aff23d815' 87 | } 88 | $JsonConfigFilePath = "$(Agent.BuildDirectory)\self\tools\aide-userconfig.json" 89 | $JsonTestParameters = Get-Content -Raw $JsonConfigFilePath | ConvertFrom-Json 90 | $JsonTestParameters.AksEdgeConfigFile = "$(Agent.BuildDirectory)\self\tools\aksedge-config.json" 91 | 92 | $JsonTestParameters.Azure = New-Object psobject -Property $AzureConfig 93 | $JsonTestParameters | ConvertTo-Json | Out-File "$JsonConfigFilePath" 94 | 95 | Write-Host "Executing tests from $TestPath, Results at $LogFile" 96 | Get-ChildItem -Path $TestPath 97 | & c:\windows\system32\windowspowershell\v1.0\powershell.exe -File "$TestPath\e2e.ps1" -LogFile $LogFile -JsonConfigFilePath $JsonConfigFilePath -IncludeGroup BasicLinuxNodeOnline 98 | Copy-Item -Path $LogFile -Destination "$(Build.ArtifactStagingDirectory)\e2e_junit.xml" 99 | Copy-Item -Path $TestPath\Logs-*.zip -Destination "$(Build.ArtifactStagingDirectory)\$E2E-Logs.zip" 100 | displayName: 'Run e2e.ps1' 101 | 102 | - task: PublishTestResults@2 103 | inputs: 104 | testResultsFormat: JUnit 105 | testResultsFiles: '$(Build.ArtifactStagingDirectory)/e2e_junit.xml' 106 | testRunTitle: 'AideScripts E2E Test Pass' 107 | displayName: 'Publish E2E Test Results' -------------------------------------------------------------------------------- /tools/scripts/AksEdgeRemoteDeploy/AksEdgeRemoteDeploy.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Sample script to deploy AksEdge via Arc for Servers 4 | 5 | .DESCRIPTION 6 | PowerShell script to deply AKS Edge Essentials using Arc for Server remote PowerShell script extension. 7 | For more information, check https://learn.microsoft.com/azure/azure-arc/servers/manage-vm-extensions-powershell 8 | 9 | .PARAMETER UseK8s 10 | Use K8s distribution if present - If not, use default K3S 11 | 12 | .PARAMETER Tag 13 | Release Tag of AKS Edge Essentials release artifacts 14 | For more information, check https://github.com/Azure/AKS-Edge/releases 15 | 16 | .PARAMETER GetManagedServiceToken 17 | Get the Managed Service Token of the AKS Edge Essentials cluster and print it out in the logs. 18 | #> 19 | param( 20 | [Switch] $UseK8s, 21 | [string] $Tag, 22 | [Switch] $GetManagedServiceToken 23 | ) 24 | #Requires -RunAsAdministrator 25 | New-Variable -Name gAksEdgeRemoteDeployVersion -Value "1.0.250311.1500" -Option Constant -ErrorAction SilentlyContinue 26 | if (! [Environment]::Is64BitProcess) { 27 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 28 | exit -1 29 | } 30 | Push-Location $PSScriptRoot 31 | $installDir = "C:\AksEdgeScript" 32 | $productName = "AKS Edge Essentials - K3s" 33 | $networkplugin = "flannel" 34 | if ($UseK8s) { 35 | $productName ="AKS Edge Essentials - K8s" 36 | $networkplugin = "calico" 37 | } 38 | 39 | # Here string for the json content 40 | $aideuserConfig = @" 41 | { 42 | "SchemaVersion": "1.3", 43 | "Version": "1.0", 44 | "AksEdgeProduct": "$productName", 45 | "AksEdgeProductUrl": "", 46 | "Azure": { 47 | "SubscriptionName": "", 48 | "SubscriptionId": "", 49 | "TenantId": "", 50 | "ResourceGroupName": "aksedge-rg", 51 | "ServicePrincipalName": "aksedge-sp", 52 | "Location": "", 53 | "CustomLocationOID":"", 54 | "Auth":{ 55 | "ServicePrincipalId":"", 56 | "Password":"" 57 | }, 58 | "ConnectedMachineName": "" 59 | }, 60 | "AksEdgeConfigFile": "aksedge-config.json" 61 | } 62 | "@ 63 | $aksedgeConfig = @" 64 | { 65 | "SchemaVersion": "1.15", 66 | "Version": "1.0", 67 | "DeploymentType": "SingleMachineCluster", 68 | "Init": { 69 | "ServiceIPRangeSize": 10, 70 | "KmsPlugin":{ 71 | "Enable": false 72 | } 73 | }, 74 | "Network": { 75 | "NetworkPlugin": "$networkplugin", 76 | "InternetDisabled": false 77 | }, 78 | "User": { 79 | "AcceptEula": true, 80 | "AcceptOptionalTelemetry": true 81 | }, 82 | "Machines": [ 83 | { 84 | "LinuxNode": { 85 | "CpuCount": 4, 86 | "MemoryInMB": 4096, 87 | "DataSizeInGB": 20 88 | } 89 | } 90 | ] 91 | } 92 | "@ 93 | 94 | ### 95 | # Main 96 | ### 97 | if (-not (Test-Path -Path $installDir)) { 98 | Write-Host "Creating $installDir..." 99 | New-Item -Path "$installDir" -ItemType Directory | Out-Null 100 | } 101 | 102 | $starttime = Get-Date 103 | $starttimeString = $($starttime.ToString("yyMMdd-HHmm")) 104 | $transcriptFile = "$PSScriptRoot\aksedgedlog-$starttimeString.txt" 105 | Start-Transcript -Path $transcriptFile 106 | 107 | Set-ExecutionPolicy Bypass -Scope Process -Force 108 | # Download the AksEdgeDeploy modules from Azure/AksEdge 109 | 110 | $url = "https://github.com/Azure/AKS-Edge/archive/main.zip" 111 | $zipFile = "main-$starttimeString.zip" 112 | $workdir = "$installDir\AKS-Edge-main" 113 | if (-Not [string]::IsNullOrEmpty($Tag)) { 114 | $url = "https://github.com/Azure/AKS-Edge/archive/refs/tags/$Tag.zip" 115 | $zipFile = "$Tag.zip" 116 | $workdir = "$installDir\AKS-Edge-$tag" 117 | } 118 | Write-Host "Step 1 : Azure/AKS-Edge repo setup" 119 | 120 | if (!(Test-Path -Path "$installDir\$zipFile")) { 121 | try { 122 | Invoke-WebRequest -Uri $url -OutFile $installDir\$zipFile -UseBasicParsing 123 | } catch { 124 | Write-Host "Error: Downloading Aide Powershell Modules failed" -ForegroundColor Red 125 | Stop-Transcript | Out-Null 126 | Pop-Location 127 | exit -1 128 | } 129 | } 130 | if (!(Test-Path -Path "$workdir")) { 131 | Expand-Archive -Path $installDir\$zipFile -DestinationPath "$installDir" -Force 132 | } 133 | 134 | $aidejson = (Get-ChildItem -Path "$workdir" -Filter aide-userconfig.json -Recurse).FullName 135 | Set-Content -Path $aidejson -Value $aideuserConfig -Force 136 | $aksedgejson = (Get-ChildItem -Path "$workdir" -Filter aksedge-config.json -Recurse).FullName 137 | Set-Content -Path $aksedgejson -Value $aksedgeConfig -Force 138 | 139 | $aksedgeShell = (Get-ChildItem -Path "$workdir" -Filter AksEdgeShell.ps1 -Recurse).FullName 140 | . $aksedgeShell 141 | 142 | # Download, install and deploy AKS EE 143 | Write-Host "Step 2: Download, install and deploy AKS Edge Essentials" 144 | # invoke the workflow, the json file already updated above. 145 | $retval = Start-AideWorkflow -jsonFile $aidejson 146 | # report error via Write-Error for Intune to show proper status 147 | if ($retval) { 148 | Write-Host "Deployment Successful. " 149 | } else { 150 | Write-Error -Message "Deployment failed" -Category OperationStopped 151 | Stop-Transcript | Out-Null 152 | Pop-Location 153 | exit -1 154 | } 155 | 156 | Write-Host "Step 3: Connect to Arc" 157 | $status = Initialize-AideArc 158 | if ($status){ 159 | Write-Host "Connecting to Azure Arc" 160 | if (Connect-AideArc) { 161 | Write-Host "Azure Arc connections successful." 162 | } else { 163 | Write-Error -Message "Azure Arc connections failed" -Category OperationStopped 164 | Stop-Transcript | Out-Null 165 | Pop-Location 166 | exit -1 167 | } 168 | } else { Write-Host "Error: Arc Initialization failed. Skipping Arc Connection" -ForegroundColor Red } 169 | 170 | if ($GetManagedServiceToken.IsPresent) 171 | { 172 | Write-Host "Step 4: Get AKS Edge managed service token" 173 | Get-AksEdgeManagedServiceToken 174 | } 175 | 176 | $endtime = Get-Date 177 | $duration = ($endtime - $starttime) 178 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 179 | Stop-Transcript | Out-Null 180 | Pop-Location 181 | exit 0 182 | -------------------------------------------------------------------------------- /tools/scripts/network/AksEdge-ListUsedIPv4s.ps1: -------------------------------------------------------------------------------- 1 | function Convert-IPtoInt64 ($ip) { 2 | $octets = $ip.split(".") 3 | [int64]([int64]$octets[0] * 16777216 + [int64]$octets[1] * 65536 + [int64]$octets[2] * 256 + [int64]$octets[3]) 4 | } 5 | 6 | function Convert-Int64toIP ([int64]$int) { 7 | (([math]::truncate($int / 16777216)).tostring() + "." + ([math]::truncate(($int % 16777216) / 65536)).tostring() + "." + ([math]::truncate(($int % 65536) / 256)).tostring() + "." + ([math]::truncate($int % 256)).tostring() ) 8 | } 9 | 10 | function Get-Subnet { 11 | <# 12 | .SYNOPSIS 13 | Code forked from https://www.powershellgallery.com/packages/Subnet/1.0.9/Content/Public%5CGet-Subnet.ps1 14 | #> 15 | Param ( 16 | [string] 17 | $IP, 18 | 19 | [ValidateRange(0, 32)] 20 | [int] 21 | $MaskBits, 22 | 23 | [switch] 24 | $Force 25 | ) 26 | Process { 27 | 28 | If ($PSBoundParameters.ContainsKey('MaskBits')) { 29 | $Mask = $MaskBits 30 | } 31 | 32 | If (-not $IP) { 33 | $LocalIP = (Get-NetIPAddress | Where-Object { $_.AddressFamily -eq 'IPv4' -and $_.PrefixOrigin -ne 'WellKnown' }) 34 | 35 | $IP = $LocalIP.IPAddress 36 | If ($Mask -notin 0..32) { $Mask = $LocalIP.PrefixLength } 37 | } 38 | 39 | If ($IP -match '/\d') { 40 | $IPandMask = $IP -Split '/' 41 | $IP = $IPandMask[0] 42 | $Mask = $IPandMask[1] 43 | } 44 | 45 | $IPAddr = [Net.IPAddress]::Parse($IP) 46 | 47 | $Class = Switch ($IP.Split('.')[0]) { 48 | { $_ -in 0..127 } { 'A' } 49 | { $_ -in 128..191 } { 'B' } 50 | { $_ -in 192..223 } { 'C' } 51 | { $_ -in 224..239 } { 'D' } 52 | { $_ -in 240..255 } { 'E' } 53 | 54 | } 55 | 56 | If ($Mask -notin 0..32) { 57 | $Mask = Switch ($Class) { 58 | 'A' { 8 } 59 | 'B' { 16 } 60 | 'C' { 24 } 61 | default { Throw "Subnet mask size was not specified and could not be inferred because the address is Class $Class." } 62 | } 63 | 64 | Write-Host "Subnet mask size was not specified. Using default subnet size for a Class $Class network of /$Mask." -ForegroundColor Yellow 65 | } 66 | 67 | $MaskAddr = [IPAddress]::Parse((Convert-Int64toIP -int ([convert]::ToInt64(("1" * $Mask + "0" * (32 - $Mask)), 2)))) 68 | $NetworkAddr = [IPAddress]($MaskAddr.address -band $IPAddr.address) 69 | $BroadcastAddr = [IPAddress](([IPAddress]::parse("255.255.255.255").address -bxor $MaskAddr.address -bor $NetworkAddr.address)) 70 | 71 | $HostStartAddr = (Convert-IPtoInt64 -ip $NetworkAddr.ipaddresstostring) + 1 72 | $HostEndAddr = (Convert-IPtoInt64 -ip $broadcastaddr.ipaddresstostring) - 1 73 | 74 | $HostAddressCount = ($HostEndAddr - $HostStartAddr) + 1 75 | 76 | If ($Mask -ge 16 -or $Force) { 77 | 78 | Write-Host "`n5. Calcualting host addresses for $NetworkAddr/$Mask.." -ForegroundColor Green 79 | 80 | $HostAddresses = for ($i = $HostStartAddr; $i -le $HostEndAddr; $i++) { 81 | Convert-Int64toIP -int $i 82 | } 83 | } 84 | Else { 85 | Write-Host "Host address calculation was not performed because it would take some time for a /$Mask subnet. `nUse -Force if you want it to occur." 86 | } 87 | 88 | return $HostAddresses 89 | } 90 | } 91 | 92 | <# 93 | .DESCRIPTION 94 | This function uses Ping requests (ICMP) to discover devices on the network. Each Ping traffic is used to generate the arp-cache table. 95 | #> 96 | 97 | Write-Host "WARNING: This tool uses ICMP & ARP requests to discover free network IP addresses. Firewalls may block these requests, limiting the use of the tool. If possible, please do a manual network check of your DHCP server or IP address allocation table." -ForegroundColor Yellow 98 | Write-Host "`n1. Listing network adapters..." -ForegroundColor Green 99 | 100 | # Print all the network adapters 101 | Get-NetAdapter 102 | 103 | do 104 | { 105 | Write-Host "`n2. Select ifIndex of desired network adapter scan:" -ForegroundColor Green 106 | $inputString = Read-Host 107 | $ifIndex = $inputString -as [Int] 108 | $ifIndexOk = $ifIndex -ne $NULL -and (Get-NetAdapter -InterfaceIndex $ifIndex -ErrorAction SilentlyContinue) -ne $NULL 109 | if ( -not $ifIndexOk ) { Write-Host "Error: You must enter a valid ifIndex" -ForegroundColor Red } 110 | } 111 | until ( $ifIndexOk ) 112 | 113 | Write-Host "`n3. Selected adapter: $($(Get-NetAdapter -InterfaceIndex $ifIndex).Name)" -ForegroundColor Green 114 | 115 | # Ensure the adapter has a valid IP address and network range 116 | $netIpConfig = Get-NetIPConfiguration | Where-Object {$_.InterfaceIndex -eq $ifIndex} 117 | if(!$netIpConfig) 118 | { 119 | Write-Host "Error: $($(Get-NetAdapter -InterfaceIndex $ifIndex).Name) does not have a valid IP address. Please try again with another network adapter, or check your networking configurations." -ForegroundColor Red 120 | # Display message for 10s and then close 121 | Start-Sleep -Seconds 10 122 | return 123 | } 124 | 125 | # Get the IP Prefix length of the network 126 | do 127 | { 128 | Write-Host "`n4. Select IP Prefix Length of the network:" -ForegroundColor Green 129 | $inputString = Read-Host 130 | $ipPrefix = $inputString -as [Int] 131 | $ipPrefixOk = $ipPrefix -ne $NULL -and $ipPrefix -gt 0 -and $ipPrefix -lt 33 132 | if ( -not $ipPrefixOk ) { Write-Host "Error: You must enter a valid IP Prefix Length between 1 and 32" -ForegroundColor Red } 133 | } 134 | until ( $ipPrefixOk ) 135 | 136 | $gatewayIp = $netIpConfig.IPv4DefaultGateway.NextHop; 137 | 138 | # Get all the IP addresses of this subnet 139 | $addresses = Get-Subnet -IP $gatewayIp -MasKBits $ipPrefix -Force 140 | 141 | # Ping all the addresses 142 | Write-Host "`n6. Ping Subnet..." -ForegroundColor Green 143 | foreach ($address in $addresses) 144 | { 145 | (New-Object System.Net.NetworkInformation.Ping).SendPingAsync("$address","1000") | Out-Null 146 | } 147 | 148 | # Wait until arp-cache: complete 149 | while ($(Get-NetNeighbor).state -eq "incomplete") { 150 | Write-host " Waiting..." -ForegroundColor Yellow 151 | timeout 1 | Out-Null 152 | } 153 | 154 | # Print all the arp-cache entries 155 | Get-NetNeighbor -AddressFamily IPv4 -InterfaceIndex $ifIndex | Where-Object -Property state -ne Unreachable | select IPaddress,LinkLayerAddress,State, @{n="Hostname"; e={(Resolve-DnsName $_.IPaddress).NameHost}} | Out-GridView 156 | 157 | if ($Host.Name -eq "ConsoleHost") 158 | { 159 | Write-Host "`n4. Press any key to continue..." -ForegroundColor Green 160 | $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null 161 | } 162 | -------------------------------------------------------------------------------- /tools/scripts/AksEdgeQuickStart/AksEdgeQuickStart.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | QuickStart script for setting up Azure for AKS Edge Essentials and deploying the same on the Windows device 3 | #> 4 | param( 5 | [Parameter(Mandatory)] 6 | [String] $SubscriptionId, 7 | [Parameter(Mandatory)] 8 | [String] $TenantId, 9 | [Parameter(Mandatory)] 10 | [String] $Location, 11 | [Switch] $UseK8s, 12 | [string] $Tag 13 | ) 14 | #Requires -RunAsAdministrator 15 | New-Variable -Name gAksEdgeQuickStartVersion -Value "1.0.250311.1500" -Option Constant -ErrorAction SilentlyContinue 16 | 17 | New-Variable -Option Constant -ErrorAction SilentlyContinue -Name arcLocations -Value @( 18 | "australiaeast","brazilsouth","canadacentral","canadaeast","centralindia","centralus","centraluseuap", 19 | "eastasia","eastus","eastus2","eastus2euap","francecentral","germanywestcentral","israelcentral", 20 | "italynorth","japaneast","koreacentral","northcentralus","northeurope","norwayeast","southafricanorth", 21 | "southcentralus","southeastasia","southindia","swedencentral","switzerlandnorth","uaenorth","uksouth", 22 | "ukwest","westcentralus","westeurope","westus","westus2","westus3" 23 | ) 24 | 25 | if (! [Environment]::Is64BitProcess) { 26 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 27 | exit -1 28 | } 29 | #Validate inputs 30 | if ($arcLocations -inotcontains $Location) { 31 | Write-Host "Error: Location $Location is not supported for Azure Arc" -ForegroundColor Red 32 | Write-Host "Supported Locations : $arcLocations" 33 | exit -1 34 | } 35 | 36 | $installDir = $((Get-Location).Path) 37 | $productName = "AKS Edge Essentials - K3s" 38 | $networkplugin = "flannel" 39 | if ($UseK8s) { 40 | $productName ="AKS Edge Essentials - K8s" 41 | $networkplugin = "calico" 42 | } 43 | 44 | # Here string for the json content 45 | $aideuserConfig = @" 46 | { 47 | "SchemaVersion": "1.3", 48 | "Version": "1.0", 49 | "AksEdgeProduct": "$productName", 50 | "AksEdgeProductUrl": "", 51 | "Azure": { 52 | "SubscriptionName": "", 53 | "SubscriptionId": "$SubscriptionId", 54 | "TenantId": "$TenantId", 55 | "ResourceGroupName": "aksedge-rg", 56 | "ServicePrincipalName": "aksedge-sp", 57 | "Location": "$Location", 58 | "CustomLocationOID":"", 59 | "Auth":{ 60 | "ServicePrincipalId":"", 61 | "Password":"" 62 | }, 63 | "ConnectedMachineName": "" 64 | }, 65 | "AksEdgeConfigFile": "aksedge-config.json" 66 | } 67 | "@ 68 | $aksedgeConfig = @" 69 | { 70 | "SchemaVersion": "1.16", 71 | "Version": "1.0", 72 | "DeploymentType": "SingleMachineCluster", 73 | "Init": { 74 | "ServiceIPRangeSize": 10, 75 | "KmsPlugin":{ 76 | "Enable": true 77 | } 78 | }, 79 | "Network": { 80 | "NetworkPlugin": "$networkplugin", 81 | "InternetDisabled": false 82 | }, 83 | "User": { 84 | "AcceptEula": true, 85 | "AcceptOptionalTelemetry": true 86 | }, 87 | "Machines": [ 88 | { 89 | "LinuxNode": { 90 | "CpuCount": 4, 91 | "MemoryInMB": 4096, 92 | "DataSizeInGB": 20 93 | } 94 | } 95 | ] 96 | } 97 | "@ 98 | 99 | ### 100 | # Main 101 | ### 102 | if (-not (Test-Path -Path $installDir)) { 103 | Write-Host "Creating $installDir..." 104 | New-Item -Path "$installDir" -ItemType Directory | Out-Null 105 | } 106 | 107 | $starttime = Get-Date 108 | $starttimeString = $($starttime.ToString("yyMMdd-HHmm")) 109 | $transcriptFile = "$installDir\aksedgedlog-$starttimeString.txt" 110 | 111 | Start-Transcript -Path $transcriptFile 112 | 113 | Set-ExecutionPolicy Bypass -Scope Process -Force 114 | # Download the AksEdgeDeploy modules from Azure/AksEdge 115 | $fork ="Azure" 116 | $branch="main" 117 | $url = "https://github.com/$fork/AKS-Edge/archive/$branch.zip" 118 | $zipFile = "AKS-Edge-$branch.zip" 119 | $workdir = "$installDir\AKS-Edge-$branch" 120 | if (-Not [string]::IsNullOrEmpty($Tag)) { 121 | $url = "https://github.com/Azure/AKS-Edge/archive/refs/tags/$Tag.zip" 122 | $zipFile = "$Tag.zip" 123 | $workdir = "$installDir\AKS-Edge-$tag" 124 | } 125 | Write-Host "Step 1 : Azure/AKS-Edge repo setup" 126 | 127 | if (!(Test-Path -Path "$installDir\$zipFile")) { 128 | try { 129 | Invoke-WebRequest -Uri $url -OutFile $installDir\$zipFile -UseBasicParsing 130 | } catch { 131 | Write-Host "Error: Downloading Aide Powershell Modules failed" -ForegroundColor Red 132 | Stop-Transcript | Out-Null 133 | Pop-Location 134 | exit -1 135 | } 136 | } 137 | if (!(Test-Path -Path "$workdir")) { 138 | Expand-Archive -Path $installDir\$zipFile -DestinationPath "$installDir" -Force 139 | } 140 | 141 | $aidejson = (Get-ChildItem -Path "$workdir" -Filter aide-userconfig.json -Recurse).FullName 142 | Set-Content -Path $aidejson -Value $aideuserConfig -Force 143 | $aksedgejson = (Get-ChildItem -Path "$workdir" -Filter aksedge-config.json -Recurse).FullName 144 | Set-Content -Path $aksedgejson -Value $aksedgeConfig -Force 145 | 146 | $aksedgeShell = (Get-ChildItem -Path "$workdir" -Filter AksEdgeShell.ps1 -Recurse).FullName 147 | . $aksedgeShell 148 | 149 | # Setup Azure 150 | Write-Host "Step 2: Setup Azure Cloud for Arc connections" 151 | $azcfg = (Get-AideUserConfig).Azure 152 | if ($azcfg.Auth.Password) { 153 | Write-Host "Password found in json spec. Skipping AksEdgeAzureSetup." -ForegroundColor Cyan 154 | } else { 155 | $aksedgeazuresetup = (Get-ChildItem -Path "$workdir" -Filter AksEdgeAzureSetup.ps1 -Recurse).FullName 156 | & $aksedgeazuresetup -jsonFile $aidejson -spContributorRole -spCredReset 157 | 158 | if ($LastExitCode -eq -1) { 159 | Write-Host "Error in configuring Azure Cloud for Arc connection" -ForegroundColor Red 160 | Stop-Transcript | Out-Null 161 | Pop-Location 162 | exit -1 163 | } 164 | } 165 | 166 | # Download, install and deploy AKS EE 167 | Write-Host "Step 3: Download, install and deploy AKS Edge Essentials" 168 | # invoke the workflow, the json file already updated above. 169 | $retval = Start-AideWorkflow -jsonFile $aidejson 170 | if ($retval) { 171 | Write-Host "Deployment Successful. " 172 | } else { 173 | Write-Error -Message "Deployment failed" -Category OperationStopped 174 | Stop-Transcript | Out-Null 175 | Pop-Location 176 | exit -1 177 | } 178 | 179 | Write-Host "Step 4: Connect to Arc Server" 180 | Write-Host "Installing required Az Powershell modules" 181 | $arcstatus = Initialize-AideArc 182 | if ($arcstatus) { 183 | Write-Host ">Connecting to Azure Arc" 184 | if (Connect-AideArcServer) { 185 | Write-Host "Azure Arc Server connection successful." 186 | } else { 187 | Write-Host "Error: Azure Arc Server connections failed" -ForegroundColor Red 188 | Stop-Transcript | Out-Null 189 | Pop-Location 190 | exit -1 191 | } 192 | } else { 193 | Write-Host "Error: Arc Initialization failed. Skipping Arc Server Connection" -ForegroundColor Red 194 | } 195 | 196 | $endtime = Get-Date 197 | $duration = ($endtime - $starttime) 198 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 199 | Stop-Transcript | Out-Null 200 | Pop-Location 201 | exit 0 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # VSCode 40 | .vscode 41 | 42 | # Visual Studio 2017 auto generated files 43 | Generated\ Files/ 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUnit 50 | *.VisualState.xml 51 | TestResult.xml 52 | nunit-*.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # StyleCop 68 | StyleCopReport.xml 69 | 70 | # Files built by Visual Studio 71 | *_i.c 72 | *_p.c 73 | *_h.h 74 | *.ilk 75 | *.meta 76 | *.obj 77 | *.iobj 78 | *.pch 79 | *.pdb 80 | *.ipdb 81 | *.pgc 82 | *.pgd 83 | *.rsp 84 | *.sbr 85 | *.tlb 86 | *.tli 87 | *.tlh 88 | *.tmp 89 | *.tmp_proj 90 | *_wpftmp.csproj 91 | *.log 92 | *.vspscc 93 | *.vssscc 94 | .builds 95 | *.pidb 96 | *.svclog 97 | *.scc 98 | 99 | # Chutzpah Test files 100 | _Chutzpah* 101 | 102 | # Visual C++ cache files 103 | ipch/ 104 | *.aps 105 | *.ncb 106 | *.opendb 107 | *.opensdf 108 | *.sdf 109 | *.cachefile 110 | *.VC.db 111 | *.VC.VC.opendb 112 | 113 | # Visual Studio profiler 114 | *.psess 115 | *.vsp 116 | *.vspx 117 | *.sap 118 | 119 | # Visual Studio Trace Files 120 | *.e2e 121 | 122 | # TFS 2012 Local Workspace 123 | $tf/ 124 | 125 | # Guidance Automation Toolkit 126 | *.gpState 127 | 128 | # ReSharper is a .NET coding add-in 129 | _ReSharper*/ 130 | *.[Rr]e[Ss]harper 131 | *.DotSettings.user 132 | 133 | # TeamCity is a build add-in 134 | _TeamCity* 135 | 136 | # DotCover is a Code Coverage Tool 137 | *.dotCover 138 | 139 | # AxoCover is a Code Coverage Tool 140 | .axoCover/* 141 | !.axoCover/settings.json 142 | 143 | # Visual Studio code coverage results 144 | *.coverage 145 | *.coveragexml 146 | 147 | # NCrunch 148 | _NCrunch_* 149 | .*crunch*.local.xml 150 | nCrunchTemp_* 151 | 152 | # MightyMoose 153 | *.mm.* 154 | AutoTest.Net/ 155 | 156 | # Web workbench (sass) 157 | .sass-cache/ 158 | 159 | # Installshield output folder 160 | [Ee]xpress/ 161 | 162 | # DocProject is a documentation generator add-in 163 | DocProject/buildhelp/ 164 | DocProject/Help/*.HxT 165 | DocProject/Help/*.HxC 166 | DocProject/Help/*.hhc 167 | DocProject/Help/*.hhk 168 | DocProject/Help/*.hhp 169 | DocProject/Help/Html2 170 | DocProject/Help/html 171 | 172 | # Click-Once directory 173 | publish/ 174 | 175 | # Publish Web Output 176 | *.[Pp]ublish.xml 177 | *.azurePubxml 178 | # Note: Comment the next line if you want to checkin your web deploy settings, 179 | # but database connection strings (with potential passwords) will be unencrypted 180 | *.pubxml 181 | *.publishproj 182 | 183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 184 | # checkin your Azure Web App publish settings, but sensitive information contained 185 | # in these scripts will be unencrypted 186 | PublishScripts/ 187 | 188 | # NuGet Packages 189 | *.nupkg 190 | # NuGet Symbol Packages 191 | *.snupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | *.appxbundle 217 | *.appxupload 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- [Bb]ackup.rdl 268 | *- [Bb]ackup ([0-9]).rdl 269 | *- [Bb]ackup ([0-9][0-9]).rdl 270 | 271 | # Microsoft Fakes 272 | FakesAssemblies/ 273 | 274 | # GhostDoc plugin setting file 275 | *.GhostDoc.xml 276 | 277 | # Node.js Tools for Visual Studio 278 | .ntvs_analysis.dat 279 | node_modules/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/paket.exe 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # CodeRush personal settings 306 | .cr/personal 307 | 308 | # Python Tools for Visual Studio (PTVS) 309 | __pycache__/ 310 | *.pyc 311 | 312 | # Cake - Uncomment if you are using it 313 | # tools/** 314 | # !tools/packages.config 315 | 316 | # Tabs Studio 317 | *.tss 318 | 319 | # Telerik's JustMock configuration file 320 | *.jmconfig 321 | 322 | # BizTalk build output 323 | *.btp.cs 324 | *.btm.cs 325 | *.odx.cs 326 | *.xsd.cs 327 | 328 | # OpenCover UI analysis results 329 | OpenCover/ 330 | 331 | # Azure Stream Analytics local run output 332 | ASALocalRun/ 333 | 334 | # MSBuild Binary and Structured Log 335 | *.binlog 336 | 337 | # NVidia Nsight GPU debugger configuration file 338 | *.nvuser 339 | 340 | # MFractors (Xamarin productivity tool) working folder 341 | .mfractor/ 342 | 343 | # Local History for Visual Studio 344 | .localhistory/ 345 | 346 | # BeatPulse healthcheck temp database 347 | healthchecksdb 348 | 349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 350 | MigrationBackup/ 351 | 352 | # Ionide (cross platform F# VS Code tools) working folder 353 | .ionide/ 354 | -------------------------------------------------------------------------------- /tools/scripts/AksEdgeQuickStart/AksEdgeQuickStart-v2.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | QuickStart script for setting up Azure for AKS Edge Essentials and deploying the same on the Windows device 3 | #> 4 | param( 5 | [Parameter(Mandatory)] 6 | [String] $AideUserConfigFilePath, 7 | [Parameter(Mandatory)] 8 | [string] $AksEdgeConfigFilePath, 9 | [string] $Tag 10 | ) 11 | #Requires -RunAsAdministrator 12 | New-Variable -Name gAksEdgeQuickStartVersion-v2 -Value "1.0.240904.1500" -Option Constant -ErrorAction SilentlyContinue 13 | 14 | New-Variable -Option Constant -ErrorAction SilentlyContinue -Name arcLocations -Value @( 15 | "southcentralus", "westus", "westus2", "westus3", "centralus", "eastus", "eastus2", "eastus3", "westcentralus", "northcentralus", "brazilsouth", 16 | "brazilsoutheast", "canadacentral", "canadaeast", "chilenorthcentral", "mexicocentral", "usgovvirginia", "usdodcentral", "usdodeast", "usgovarizona", 17 | "usgovtexas", "usseceast", "ussecwest", "ussecwestcentral", "eastasia", "southeastasia", "australiaeast", "australiasoutheast", "australiacentral", 18 | "australiacentral2", "chinaeast", "chinaeast2", "chinanorth", "chinanorth2", "chinanorth3", "centralindia", "southindia", "westindia", "indonesiacentral", 19 | "japaneast", "japanwest", "koreacentral", "koreasouth", "malaysiawest", "newzealandnorth", "taiwan", "austriaeast", "belgiumcentral", "denmarkeast", 20 | "northeurope", "westeurope", "finlandcentral", "francecentral", "francesouth", "germanywestcentral", "germanynortheast", "germanycentral", "germanynorth", 21 | "greece", "italynorth", "norwayeast", "norwaywest", "polandcentral", "spaincentral", "swedencentral", "swedensouth", "switzerlandnorth", 22 | "switzerlandwest", "uksouth", "ukwest", "southafricanorth", "southafricawest", "israelcentral", "qatarcentral", "uaenorth", "uaecentral" 23 | ) 24 | 25 | New-Variable -Option Constant -ErrorAction SilentlyContinue -Name AksEdgeProductType -Value @( 26 | "AKS Edge Essentials - K3s", "AKS Edge Essentials - K8s" 27 | ) 28 | 29 | if (! [Environment]::Is64BitProcess) { 30 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 31 | exit -1 32 | } 33 | #Check provided filepaths, and retrieve respective json string 34 | if (!(Test-Path -Path "$AideUserConfigFilePath" -PathType Leaf)) 35 | { 36 | $msg = "Aide-user config file '$AideUserConfigFilePath' could not be found or accessed" 37 | Write-Host $msg -ForegroundColor Red 38 | exit -1 39 | } 40 | try 41 | { 42 | $aideuserConfig = Get-Content "$AideUserConfigFilePath" 43 | } 44 | catch 45 | { 46 | $err = $_.Exception.Message.ToString() 47 | $msg = "Failed to read Aide-user config file contents. Error was: $err" 48 | Write-Host $msg -ForegroundColor Red 49 | exit -1 50 | } 51 | 52 | if (!(Test-Path -Path "$AksEdgeConfigFilePath" -PathType Leaf)) 53 | { 54 | $msg = "Aks-Edge config file '$AksEdgeConfigFilePath' could not be found or accessed" 55 | Write-Host $msg -ForegroundColor Red 56 | exit -1 57 | } 58 | try 59 | { 60 | $aksedgeConfig = Get-Content "$AksEdgeConfigFilePath" 61 | } 62 | catch 63 | { 64 | $err = $_.Exception.Message.ToString() 65 | $msg = "Failed to read Aks-Edge config file contents. Error was: $err" 66 | Write-Host $msg -ForegroundColor Red 67 | exit -1 68 | } 69 | 70 | #Validate inputs 71 | try 72 | { 73 | $aideConfigObj = ($aideuserConfig| ConvertFrom-Json) 74 | } 75 | catch 76 | { 77 | $err = $_.Exception.Message.ToString() 78 | $msg = "Failed to parse aide config string. Error was: $err" 79 | Write-Host $msg -ForegroundColor Red 80 | exit -1 81 | } 82 | if ([string]::IsNullOrEmpty($aideConfigObj.AksEdgeProduct) -or $AksEdgeProductType -notcontains $aideConfigObj.AksEdgeProduct) 83 | { 84 | Write-Host "Error: AideUserConfig.AksEdgeProduct $($aideConfigObj.AksEdgeProduct) is invalid" -ForegroundColor Red 85 | Write-Host "Supported values: $AksEdgeProductType" 86 | exit -1 87 | } 88 | $skipAzureArc = $false 89 | if ([string]::IsNullOrEmpty($aideConfigObj.Azure.SubscriptionId)) { 90 | Write-Host "Warning: Require SubscriptionId for Azure Arc" -ForegroundColor Cyan 91 | $skipAzureArc = $true 92 | } 93 | if ([string]::IsNullOrEmpty($aideConfigObj.Azure.TenantId)) { 94 | Write-Host "Warning: Require TenantId for Azure Arc" -ForegroundColor Cyan 95 | $skipAzureArc = $true 96 | } 97 | if ([string]::IsNullOrEmpty($aideConfigObj.Azure.Location)) { 98 | Write-Host "Warning: Require Location for Azure Arc" -ForegroundColor Cyan 99 | $skipAzureArc = $true 100 | } elseif ($arcLocations -inotcontains $aideConfigObj.Azure.Location) { 101 | Write-Host "Error: Location $($aideConfigObj.Azure.Location) is not supported for Azure Arc" -ForegroundColor Red 102 | Write-Host "Supported Locations : $arcLocations" 103 | exit -1 104 | } 105 | if ($skipAzureArc) { 106 | Write-Host "Azure setup and Arc connection will be skipped as required details are not available" -ForegroundColor Yellow 107 | } 108 | 109 | $installDir = $((Get-Location).Path) 110 | 111 | ### 112 | # Main 113 | ### 114 | if (-not (Test-Path -Path $installDir)) { 115 | Write-Host "Creating $installDir..." 116 | New-Item -Path "$installDir" -ItemType Directory | Out-Null 117 | } 118 | 119 | $starttime = Get-Date 120 | $starttimeString = $($starttime.ToString("yyMMdd-HHmm")) 121 | $transcriptFile = "$installDir\aksedgedlog-$starttimeString.txt" 122 | 123 | Start-Transcript -Path $transcriptFile 124 | 125 | Set-ExecutionPolicy Bypass -Scope Process -Force 126 | # Download the AksEdgeDeploy modules from Azure/AksEdge 127 | $fork ="Azure" 128 | $branch="main" 129 | $url = "https://github.com/$fork/AKS-Edge/archive/$branch.zip" 130 | $zipFile = "AKS-Edge-$branch.zip" 131 | $workdir = "$installDir\AKS-Edge-$branch" 132 | if (-Not [string]::IsNullOrEmpty($Tag)) { 133 | $url = "https://github.com/Azure/AKS-Edge/archive/refs/tags/$Tag.zip" 134 | $zipFile = "$Tag.zip" 135 | $workdir = "$installDir\AKS-Edge-$Tag" 136 | } 137 | Write-Host "Step 1 : Azure/AKS-Edge repo setup" 138 | 139 | if (!(Test-Path -Path "$installDir\$zipFile")) { 140 | try { 141 | Invoke-WebRequest -Uri $url -OutFile $installDir\$zipFile -UseBasicParsing 142 | } catch { 143 | Write-Host "Error: Downloading Aide Powershell Modules failed" -ForegroundColor Red 144 | Stop-Transcript | Out-Null 145 | Pop-Location 146 | exit -1 147 | } 148 | } 149 | if (!(Test-Path -Path "$workdir")) { 150 | Expand-Archive -Path $installDir\$zipFile -DestinationPath "$installDir" -Force 151 | } 152 | 153 | $aidejson = (Get-ChildItem -Path "$workdir" -Filter aide-userconfig.json -Recurse).FullName 154 | Set-Content -Path $aidejson -Value $aideuserConfig -Force 155 | $aksedgejson = (Get-ChildItem -Path "$workdir" -Filter aksedge-config.json -Recurse).FullName 156 | Set-Content -Path $aksedgejson -Value $aksedgeConfig -Force 157 | 158 | $aksedgeShell = (Get-ChildItem -Path "$workdir" -Filter AksEdgeShell.ps1 -Recurse).FullName 159 | . $aksedgeShell 160 | 161 | # Setup Azure 162 | Write-Host "Step 2: Setup Azure Cloud for Arc connections" 163 | $azcfg = (Get-AideUserConfig).Azure 164 | if ($azcfg.Auth.Password) { 165 | Write-Host "Password found in json spec. Skipping AksEdgeAzureSetup." -ForegroundColor Cyan 166 | $skipAzureArc = $false 167 | } elseif ($skipAzureArc) { 168 | Write-Host ">> skipping step 2" -ForegroundColor Yellow 169 | } else { 170 | $aksedgeazuresetup = (Get-ChildItem -Path "$workdir" -Filter AksEdgeAzureSetup.ps1 -Recurse).FullName 171 | & $aksedgeazuresetup -jsonFile $aidejson -spContributorRole -spCredReset 172 | 173 | if ($LastExitCode -eq -1) { 174 | Write-Host "Error in configuring Azure Cloud for Arc connection" -ForegroundColor Red 175 | Stop-Transcript | Out-Null 176 | Pop-Location 177 | exit -1 178 | } 179 | } 180 | 181 | # Download, install and deploy AKS EE 182 | Write-Host "Step 3: Download, install and deploy AKS Edge Essentials" 183 | # invoke the workflow, the json file already updated above. 184 | $retval = Start-AideWorkflow -jsonFile $aidejson 185 | if ($retval) { 186 | Write-Host "Deployment Successful. " 187 | } else { 188 | Write-Error -Message "Deployment failed" -Category OperationStopped 189 | Stop-Transcript | Out-Null 190 | Pop-Location 191 | exit -1 192 | } 193 | 194 | Write-Host "Step 4: Connect to Arc" 195 | if ($skipAzureArc) { 196 | Write-Host ">> skipping step 4" -ForegroundColor Yellow 197 | } else { 198 | Write-Host "Installing required Az Powershell modules" 199 | $arcstatus = Initialize-AideArc 200 | if ($arcstatus) { 201 | Write-Host ">Connecting to Azure Arc" 202 | if (Connect-AideArc) { 203 | Write-Host "Azure Arc connections successful." 204 | } else { 205 | Write-Host "Error: Azure Arc connections failed" -ForegroundColor Red 206 | Stop-Transcript | Out-Null 207 | Pop-Location 208 | exit -1 209 | } 210 | } else { Write-Host "Error: Arc Initialization failed. Skipping Arc Connection" -ForegroundColor Red } 211 | } 212 | 213 | $endtime = Get-Date 214 | $duration = ($endtime - $starttime) 215 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 216 | Stop-Transcript | Out-Null 217 | Pop-Location 218 | exit 0 -------------------------------------------------------------------------------- /samples/others/container-azm-ms-agentconfig.yml: -------------------------------------------------------------------------------- 1 | kind: ConfigMap 2 | apiVersion: v1 3 | data: 4 | schema-version: 5 | #string.used by agent to parse config. supported versions are {v1}. Configs with other schema versions will be rejected by the agent. 6 | v1 7 | config-version: 8 | #string.used by customer to keep track of this config file's version in their source control/repository (max allowed 10 chars, other chars will be truncated) 9 | ver1 10 | log-data-collection-settings: |- 11 | # Log data collection settings 12 | # Any errors related to config map settings can be found in the KubeMonAgentEvents table in the Log Analytics workspace that the cluster is sending data to. 13 | 14 | [log_collection_settings] 15 | [log_collection_settings.stdout] 16 | # In the absense of this configmap, default value for enabled is true 17 | enabled = true 18 | # exclude_namespaces setting holds good only if enabled is set to true 19 | # kube-system log collection is disabled by default in the absence of 'log_collection_settings.stdout' setting. If you want to enable kube-system, remove it from the following setting. 20 | # If you want to continue to disable kube-system log collection keep this namespace in the following setting and add any other namespace you want to disable log collection to the array. 21 | # In the absense of this configmap, default value for exclude_namespaces = ["kube-system"] 22 | # exclude_namespaces = ["kube-system"] 23 | 24 | [log_collection_settings.stderr] 25 | # Default value for enabled is true 26 | enabled = true 27 | # exclude_namespaces setting holds good only if enabled is set to true 28 | # kube-system log collection is disabled by default in the absence of 'log_collection_settings.stderr' setting. If you want to enable kube-system, remove it from the following setting. 29 | # If you want to continue to disable kube-system log collection keep this namespace in the following setting and add any other namespace you want to disable log collection to the array. 30 | # In the absense of this cofigmap, default value for exclude_namespaces = ["kube-system"] 31 | # exclude_namespaces = ["kube-system"] 32 | 33 | [log_collection_settings.env_var] 34 | # In the absense of this configmap, default value for enabled is true 35 | enabled = true 36 | [log_collection_settings.enrich_container_logs] 37 | # In the absense of this configmap, default value for enrich_container_logs is false 38 | enabled = false 39 | # When this is enabled (enabled = true), every container log entry (both stdout & stderr) will be enriched with container Name & container Image 40 | [log_collection_settings.collect_all_kube_events] 41 | # In the absense of this configmap, default value for collect_all_kube_events is false 42 | # When the setting is set to false, only the kube events with !normal event type will be collected 43 | enabled = false 44 | # When this is enabled (enabled = true), all kube events including normal events will be collected 45 | #[log_collection_settings.schema] 46 | # In the absence of this configmap, default value for containerlog_schema_version is "v1" 47 | # Supported values for this setting are "v1","v2" 48 | # See documentation at https://aka.ms/ContainerLogv2 for benefits of v2 schema over v1 schema before opting for "v2" schema 49 | # containerlog_schema_version = "v2" 50 | 51 | 52 | prometheus-data-collection-settings: |- 53 | # Custom Prometheus metrics data collection settings 54 | [prometheus_data_collection_settings.cluster] 55 | # Cluster level scrape endpoint(s). These metrics will be scraped from agent's Replicaset (singleton) 56 | # Any errors related to prometheus scraping can be found in the KubeMonAgentEvents table in the Log Analytics workspace that the cluster is sending data to. 57 | 58 | #Interval specifying how often to scrape for metrics. This is duration of time and can be specified for supporting settings by combining an integer value and time unit as a string value. Valid time units are ns, us (or µs), ms, s, m, h. 59 | interval = "5s" 60 | 61 | ## Uncomment the following settings with valid string arrays for prometheus scraping 62 | #fieldpass = ["node_load15", "container_cpu_usage_seconds_total"] 63 | 64 | #fielddrop = ["metric_to_drop"] 65 | 66 | # An array of urls to scrape metrics from. 67 | # urls = ["http://myurl:9101/metrics"] 68 | 69 | # An array of Kubernetes services to scrape metrics from. 70 | kubernetes_services = ["http://my-service-dns.my-namespace:9102/metrics"] 71 | 72 | # When monitor_kubernetes_pods = true, replicaset will scrape Kubernetes pods for the following prometheus annotations: 73 | # - prometheus.io/scrape: Enable scraping for this pod 74 | # - prometheus.io/scheme: If the metrics endpoint is secured then you will need to 75 | # set this to `https` & most likely set the tls config. 76 | # - prometheus.io/path: If the metrics path is not /metrics, define it with this annotation. 77 | # - prometheus.io/port: If port is not 9102 use this annotation 78 | monitor_kubernetes_pods = true 79 | 80 | ## Restricts Kubernetes monitoring to namespaces for pods that have annotations set and are scraped using the monitor_kubernetes_pods setting. 81 | ## This will take effect when monitor_kubernetes_pods is set to true 82 | ## ex: monitor_kubernetes_pods_namespaces = ["default1", "default2", "default3"] 83 | monitor_kubernetes_pods_namespaces = ["default1", "default2", "default3"] 84 | 85 | ## Label selector to target pods which have the specified label 86 | ## This will take effect when monitor_kubernetes_pods is set to true 87 | ## Reference the docs at https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors 88 | # kubernetes_label_selector = "env=dev,app=nginx" 89 | 90 | ## Field selector to target pods which have the specified field 91 | ## This will take effect when monitor_kubernetes_pods is set to true 92 | ## Reference the docs at https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/ 93 | ## eg. To scrape pods on a specific node 94 | # kubernetes_field_selector = "spec.nodeName=$HOSTNAME" 95 | 96 | [prometheus_data_collection_settings.node] 97 | # Node level scrape endpoint(s). These metrics will be scraped from agent's DaemonSet running in every node in the cluster 98 | # Any errors related to prometheus scraping can be found in the KubeMonAgentEvents table in the Log Analytics workspace that the cluster is sending data to. 99 | 100 | #Interval specifying how often to scrape for metrics. This is duration of time and can be specified for supporting settings by combining an integer value and time unit as a string value. Valid time units are ns, us (or µs), ms, s, m, h. 101 | interval = "30s" 102 | 103 | ## Uncomment the following settings with valid string arrays for prometheus scraping 104 | 105 | # An array of urls to scrape metrics from. $NODE_IP (all upper case) will substitute of running Node's IP address 106 | # urls = ["http://$NODE_IP:9103/metrics"] 107 | 108 | #fieldpass = ["metric_to_pass1", "metric_to_pass12"] 109 | 110 | #fielddrop = ["metric_to_drop"] 111 | 112 | metric_collection_settings: |- 113 | # Metrics collection settings for metrics sent to Log Analytics and MDM 114 | [metric_collection_settings.collect_kube_system_pv_metrics] 115 | # In the absense of this configmap, default value for collect_kube_system_pv_metrics is false 116 | # When the setting is set to false, only the persistent volume metrics outside the kube-system namespace will be collected 117 | enabled = true 118 | # When this is enabled (enabled = true), persistent volume metrics including those in the kube-system namespace will be collected 119 | 120 | alertable-metrics-configuration-settings: |- 121 | # Alertable metrics configuration settings for container resource utilization 122 | [alertable_metrics_configuration_settings.container_resource_utilization_thresholds] 123 | # The threshold(Type Float) will be rounded off to 2 decimal points 124 | # Threshold for container cpu, metric will be sent only when cpu utilization exceeds or becomes equal to the following percentage 125 | container_cpu_threshold_percentage = 95.0 126 | # Threshold for container memoryRss, metric will be sent only when memory rss exceeds or becomes equal to the following percentage 127 | container_memory_rss_threshold_percentage = 95.0 128 | # Threshold for container memoryWorkingSet, metric will be sent only when memory working set exceeds or becomes equal to the following percentage 129 | container_memory_working_set_threshold_percentage = 95.0 130 | 131 | # Alertable metrics configuration settings for persistent volume utilization 132 | [alertable_metrics_configuration_settings.pv_utilization_thresholds] 133 | # Threshold for persistent volume usage bytes, metric will be sent only when persistent volume utilization exceeds or becomes equal to the following percentage 134 | pv_usage_threshold_percentage = 60.0 135 | 136 | # Alertable metrics configuration settings for completed jobs count 137 | [alertable_metrics_configuration_settings.job_completion_threshold] 138 | # Threshold for completed job count , metric will be sent only for those jobs which were completed earlier than the following threshold 139 | job_completion_threshold_time_minutes = 360 140 | integrations: |- 141 | [integrations.azure_network_policy_manager] 142 | collect_basic_metrics = false 143 | collect_advanced_metrics = false 144 | [integrations.azure_subnet_ip_usage] 145 | enabled = false 146 | 147 | # Doc - https://github.com/microsoft/Docker-Provider/blob/ci_prod/Documentation/AgentSettings/ReadMe.md 148 | agent-settings: |- 149 | # prometheus scrape fluent bit settings for high scale 150 | # buffer size should be greater than or equal to chunk size else we set it to chunk size. 151 | [agent_settings.prometheus_fbit_settings] 152 | tcp_listener_chunk_size = 10 153 | tcp_listener_buffer_size = 10 154 | tcp_listener_mem_buf_limit = 200 155 | 156 | # The following settings are "undocumented", we don't recommend uncommenting them unless directed by Microsoft. 157 | # They increase the maximum stdout/stderr log collection rate but will also cause higher cpu/memory usage. 158 | # [agent_settings.fbit_config] 159 | # log_flush_interval_secs = "1" # default value is 15 160 | # tail_mem_buf_limit_megabytes = "10" # default value is 10 161 | # tail_buf_chunksize_megabytes = "1" # default value is 32kb (comment out this line for default) 162 | # tail_buf_maxsize_megabytes = "1" # defautl value is 32kb (comment out this line for default) 163 | 164 | metadata: 165 | name: container-azm-ms-agentconfig 166 | namespace: kube-system 167 | -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/README.md: -------------------------------------------------------------------------------- 1 | # AksEdgeDeploy (aide) 2 | 3 | AksEdgeDeploy module enables you to automate the AKS edge installation, deployment and provisioning easily with a simple json specification. 4 | 5 | The `Start-AideWorkflow` function in the modole does the following: 6 | 7 | - Installs the required version of the AKS edge 8 | - Validate the json parameters 9 | - Creates the required network switch 10 | - Deploys the AKS edge virtual machine with the json parameters 11 | - Verifies the AKS edge virtual machine is up and running 12 | 13 | ## Usage 14 | 15 | 1. Populate the *aide-userconfig.json* with the desired parameters and values. Below is the minimal configuration example for a single machine deployment with 4GB memory. 16 | 17 | ```json 18 | { 19 | "SchemaVersion": "1.3", 20 | "Version": "1.0", 21 | "AksEdgeProduct" : "AKS Edge Essentials - K3s", 22 | "AksEdgeConfig": { 23 | "SchemaVersion": "1.15", 24 | "Version": "1.0", 25 | "DeploymentType": "SingleMachineCluster", 26 | "Init": { 27 | "ServiceIPRangeSize": 10, 28 | "KmsPlugin": { 29 | "Enable": false 30 | } 31 | }, 32 | "Network": { 33 | "NetworkPlugin": "flannel", 34 | "InternetDisabled": false 35 | }, 36 | "User": { 37 | "AcceptEula": true, 38 | "AcceptOptionalTelemetry": true 39 | }, 40 | "Machines": [ 41 | { 42 | "LinuxNode": { 43 | "CpuCount": 4, 44 | "MemoryInMB": 4096, 45 | "DataSizeInGB": 20 46 | } 47 | } 48 | ] 49 | }, 50 | "Azure": { 51 | "SubscriptionName":"", 52 | "SubscriptionId": "", 53 | "TenantId":"", 54 | "ResourceGroupName": "aksedge-rg", 55 | "ServicePrincipalName" : "aksedge-sp", 56 | "Location" : "EastUS", 57 | "EnableWorkloadIdentity": true 58 | } 59 | } 60 | ``` 61 | 62 | 2. Call `Start-AideWorkflow` with the json file as input. This will perform the deployment. 63 | 64 | ```powershell 65 | Start-AideWorkflow -jsonFile 'C:\MyConfigs\aide-userconfig.json' 66 | ``` 67 | 68 | ## AksEdgeDeploy Config Json 69 | 70 | Find below the details of the supported parameters in the json file. 71 | 72 | |Node| Parameter | Required | Type / Values | Comments | 73 | |-| --------- | -------- |---------------- | -------- | 74 | |SchemaVersion| - | Mandatory | 1.3 | Fixed value, schema version. Reserved | 75 | |Version| - | Mandatory | 1.0 | Fixed value, json instance version | 76 | |AksEdgeProduct| - | Mandatory | AKS Edge Essentials - K8s
AKS Edge Essentials - K3s | Desired product K8s or K3s | 77 | |AksEdgeProductUrl| - | Optional | URL | URL to download the MSI | 78 | |Azure | ClusterName | Optional | String | Name of the cluster for Arc connection. Default is hostname-distribution (abc-k8s or def-k3s)| 79 | || SubscriptionName | Mandatory | String | Name of the Azure Subscription | 80 | || SubscriptionId | Optional | GUID | Azure Subscription ID | 81 | || TenantId | Optional | GUID | Azure Tenant ID | 82 | || ResourceGroupName | Mandatory | String | ResourceGroupName | 83 | || ServicePrincipalName | Mandatory | String | ServicePrincipalName | 84 | || Location | Mandatory | String | Location | 85 | || CustomLocationOID | Optional | GUID | ObjectID for the custom location resource provider | 86 | || `Auth`.ServicePrincipalId |Mandatory | GUID | Specify service principal appID to use| 87 | || `Auth`.Password |Mandatory| String | Specify the password (in clear) | 88 | || EnableWorkloadIdentity |Optional| Boolean | Enable secure workload access to azure resource (only for AIO)| 89 | || EnableKeyManagement |Optional| Boolean | Enables Key management (key rotation) (only for AIO)| 90 | || GatewayResourceId |Optional| String | Resource Id for the Arc Gateway resource (only for AIO)| 91 | || ConnectedMachineName |Optional| String | Specify the resource name for connected machine agent. Default is hostname | 92 | |InstallOptions| InstallPath | Optional | String | Path to install the product | 93 | || VhdxPath | Optional | String | Path to store the vhdx files | 94 | |VSwitch| Name | Optional | String | Name for the external switch, mandatory for ScalableCluster| 95 | || AdapterName | Optional | String | Name for the physical adapter, mandatory for ScalableCluster| 96 | |AksEdgeConfigFile| - | Optional | String | File path to the AKS Edge Configuration json. Either `AksEdgeConfig` or `AksEdgeConfigFile` needs to be specified.| 97 | |AksEdgeConfig| - | Optional | Json object | Embedded json object for AKS Edge Configuration| 98 | 99 | ![AksEdgeDeploy json](AksEdgeDeploy.png) 100 | 101 | ## AksEdge Config Json 102 | 103 | ![AksEdge Schema json](AksEdgeSchema.png) 104 | 105 | 106 | ## AKS Edge Essentials Arc Connection 107 | 108 | The following functions enables you to install and use `Arc enabled Servers` and `Arc enabled Kubernetes` easily on a windows IoT device. 109 | 110 | ### Usage 111 | 112 | 1. Populate the *aide-userconfig.json* with the desired values. 113 | 2. Run the script [`AksEdgeAzureSetup.ps1`](../../scripts/AksEdgeAzureSetup/AksEdgeAzureSetup.ps1) in the `tools\scripts\AksEdgeAzureSetup` directory to setup your Azure subscription, create the resource group, setup the required extensions and also create the service principal with minimal privileges(`Azure Connected Machine Onboarding`,`Kubernetes Cluster - Azure Arc Onboarding`). You will need to login for Azure CLI interactively for the first time to create the service principal. This step is required to be run only once per subscription. 114 | 115 | ```powershell 116 | # prompts for interactive login for serviceprincipal creation with minimal privileges 117 | cd .\scripts\AksEdgeAzureSetup 118 | .\AksEdgeAzureSetup.ps1 .\aide-userconfig.json 119 | ``` 120 | 121 | If you require to create the service principal with `Contributor` role at the resource group level, you can add the `-spContributorRole` switch. 122 | 123 | >[!Note] You will require the Contributor role if you need to disconnect your kubernetes cluster using `Disconnect-AideArcKubernetes`. 124 | To, reset an already existing service principal, use `-spCredReset`. Reset should be used cautiously. 125 | 126 | ```powershell 127 | # creates service principal with Contributor role at resource group level 128 | .\AksEdgeAzureSetup.ps1 .\aide-userconfig.json -spContributorRole 129 | ``` 130 | 131 | ```powershell 132 | # resets the existing service principal 133 | .\AksEdgeAzureSetup.ps1 .\aide-userconfig.json -spCredReset 134 | ``` 135 | 136 | ```powershell 137 | # you can test the creds with 138 | .\AksEdgeAzureSetup-Test.ps1 .\aide-userconfig.json 139 | ``` 140 | 141 | 3. Import the AksEdgeDeploy module and set the user config. 142 | 4. Run `Initialize-AideArc` to install the required software (Azure CLI) and validates that Azure setup is good. 143 | 5. `Connect-AideArcServer` to connect your machine to Arc-enabled server. 144 | 6. After installing AKS edge or any kuberenetes cluster in your Linux VM, verify with `kubectl get nodes` and then call `Connect-AideArcKubernetes` 145 | 146 | ```powershell 147 | # installs AzCLI 148 | Initialize-AideArc 149 | # Connects the Win IoT machine to Arc-enabled server 150 | Connect-AideArcServer 151 | # Prereq: install AKS edge and deploy cluster 152 | # test the cluster is good 153 | kubectl get nodes 154 | # Connect the cluster to Arc-enabled Kubernetes 155 | Connect-AideArcKubernetes 156 | ``` 157 | 158 | alternatively, you can use `Connect-AideArc` that enables both Arc-enabled server and Arc-enabled kubernetes. 159 | 160 | ```powershell 161 | # installs AzCLI 162 | Initialize-AideArc 163 | # connect both Arc-enabled server and kubernetes 164 | Connect-AideArc 165 | ``` 166 | 167 | ## Supported Functions 168 | 169 | | Functions | 170 | |:------------ | 171 | |`Start-AideWorkflow -jsonFile (or) -jsonString`| 172 | | Main funtion that validates the user config, installs AksEdge, creates switch, deploys and provisions VM | 173 | |`Connect-AideArc`| 174 | | Connects Arc-enabled server and Arc-enabled kubernetes| 175 | |`Disconnect-AideArc`| 176 | | Disconnects Arc-enabled server and Arc-enabled kubernetes| 177 | 178 |
User Config Functions 179 | 180 | | | 181 | |:------------ | 182 | |`Get-AideUserConfig`| 183 | | Returns the json object that is cached | 184 | |`Set-AideUserConfig -jsonFile (or) -jsonString`| 185 | | Sets the user config and reads the config into the cache | 186 | |`Read-AideUserConfig`| 187 | |Reads the json file into the cache | 188 | |`Test-AideUserConfig`| 189 | | Tests the User Config json for parameter correctness | 190 |
191 |
VM Switch Functions 192 | 193 | | | 194 | |:------------ | 195 | |`New-AideVmSwitch`| 196 | | Creates an new VM switch based on user config. | 197 | |`Test-AideVmSwitch -Create`| 198 | | Tests if the VM switch is present, `Create` flag invokes New-AideVmSwitch if switch is not present | 199 | |`Remove-AideVmSwitch`| 200 | | Removes the VM switch if present. Also removes the Nat if created (for internal switch) | 201 | 202 |
203 |
Deployment functions 204 | 205 | | | 206 | |:------------ | 207 | |`Invoke-AideDeployment`| 208 | | Validates the deployment parameters in user json and deploys AKS edge VM| 209 | |`Test-AideDeployment`| 210 | | Tests if the AKS edge VM is deployed (present) | 211 | |`Remove-AideDeployment`| 212 | | Removes the existing deployment | 213 | |`Test-AideLinuxVmRun`| 214 | | Tests if the AKS edge VM is running in the machine | 215 |
216 |
AksEdge MSI Install functions 217 | 218 | | | 219 | |:------------ | 220 | |`Get-AideMsiVersion`| 221 | | Returns the installed product name and version (PSCustom object with Name,Version) or Null if none found| 222 | |`Install-AideMsi`| 223 | | Installs the requested product from the aksedgeProductUrl if specified, otherwise it installs the latest (default)| 224 | |`Test-AideMsiInstall -Install`| 225 | | Tests if AKS edge is installed and `Install` switch is specified, it installs when not found| 226 | |`Remove-AideMsi`| 227 | | Removes the installed AKS edge product| 228 | |`Get-AideHostPcInfo`| 229 | | Gets the PC information such as OS version etc| 230 |
231 |
Azure Arc Install functions 232 | 233 | | | 234 | |:------------ | 235 | |`Initialize-AideArc`| 236 | | Main funtion that checks and installs required software, validates if the Auth parameters are good for Azure login | 237 | |`Enter-AideArcSession`| 238 | | Logs in to Azure using the service principal credentials| 239 | |`Exit-AideArcSession`| 240 | | Logs out from the Azure CLI session| 241 |
242 |
Azure Arc-enabled Server Functions 243 | 244 | | | 245 | |:------------ | 246 | |`Install-AideArcServer`| 247 | | Installs Azure Connected Machine Agent | 248 | |`Test-AideArcServer`| 249 | | Tests ConnectedMachine Agent status (returns true if connected) | 250 | |`Connect-AideArcServer`| 251 | | Connects the machine to Arc-enabled server | 252 | |`Disconnect-AideArcServer`| 253 | | Removes the Arc-enabled server connection | 254 | |`Get-AideArcServerInfo`| 255 | | Returns the HIMDS info (name,subscriptionid,resourcegroupname and location) from Connected machine agent | 256 | |`Get-AideArcServerSMI`| 257 | | Retrieves the system assigned managed identity for Arc-enabled server| 258 |
259 |
Azure Arc-enabled Kubernetes Functions 260 | 261 | | | 262 | |:------------ | 263 | |`Test-AideArcKubernetes`| 264 | | Tests if the kubernetes cluster is connected to Arc | 265 | |`Connect-AideArcKubernetes`| 266 | | Connects the kubernetes cluster to Arc using the default kubeconfig files | 267 | |`Disconnect-AideArcKubernetes`| 268 | | Deletes the kubernetes cluster resource in Arc | 269 | |`Get-AideArcKubernetesServiceToken`| 270 | | Retrieves the service token for admin-user in the kubernetes cluster | 271 | |`Get-AideArcClusterName`| 272 | | Retrieves the cluster name used for Arc connection | 273 |
274 | -------------------------------------------------------------------------------- /tools/scripts/AksEdgeRemoteDeploy/AksEdgeRemoteDeploy-Intune.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Sample script to deploy AksEdge via Intune 4 | 5 | .DESCRIPTION 6 | PowerShell script to deply AKS Edge Essentials using Intune 7 | In Intune, set the following for the return values 8 | -1 : Retry 9 | 2 : Hard reboot 10 | 0 : Success 11 | 12 | .PARAMETER RunToComplete 13 | Retry continuously until deployment is completed 14 | 15 | .PARAMETER UseK8s 16 | Use K8s distribution if present - If not, use default K3S 17 | 18 | .PARAMETER Tag 19 | Release Tag of AKS Edge Essentials release artifacts 20 | For more information, check https://github.com/Azure/AKS-Edge/releases 21 | #> 22 | param( 23 | [Switch] $RunToComplete, 24 | [Switch] $UseK8s, 25 | [string] $Tag 26 | ) 27 | #Requires -RunAsAdministrator 28 | New-Variable -Name gAksEdgeRemoteDeployVersion -Value "1.0.250311.1500" -Option Constant -ErrorAction SilentlyContinue 29 | if (! [Environment]::Is64BitProcess) { 30 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 31 | exit -1 32 | } 33 | 34 | $installDir = "C:\AksEdgeScript" 35 | $productName = "AKS Edge Essentials - K3s" 36 | $networkplugin = "flannel" 37 | if ($UseK8s) { 38 | $productName ="AKS Edge Essentials - K8s" 39 | $networkplugin = "calico" 40 | } 41 | 42 | # Here string for the json content 43 | $aideuserConfig = @" 44 | { 45 | "SchemaVersion": "1.3", 46 | "Version": "1.0", 47 | "AksEdgeProduct": "$productName", 48 | "AksEdgeProductUrl": "", 49 | "Azure": { 50 | "SubscriptionName": "", 51 | "SubscriptionId": "", 52 | "TenantId": "", 53 | "ResourceGroupName": "aksedge-rg", 54 | "ServicePrincipalName": "aksedge-sp", 55 | "Location": "", 56 | "CustomLocationOID":"", 57 | "Auth":{ 58 | "ServicePrincipalId":"", 59 | "Password":"" 60 | }, 61 | "ConnectedMachineName": "" 62 | }, 63 | "AksEdgeConfigFile": "aksedge-config.json" 64 | } 65 | "@ 66 | $aksedgeConfig = @" 67 | { 68 | "SchemaVersion": "1.15", 69 | "Version": "1.0", 70 | "DeploymentType": "SingleMachineCluster", 71 | "Init": { 72 | "ServiceIPRangeSize": 10, 73 | "KmsPlugin":{ 74 | "Enable": false 75 | } 76 | }, 77 | "Network": { 78 | "NetworkPlugin": "$networkplugin", 79 | "InternetDisabled": false 80 | }, 81 | "User": { 82 | "AcceptEula": true, 83 | "AcceptOptionalTelemetry": true 84 | }, 85 | "Machines": [ 86 | { 87 | "LinuxNode": { 88 | "CpuCount": 4, 89 | "MemoryInMB": 4096, 90 | "DataSizeInGB": 20 91 | } 92 | } 93 | ] 94 | } 95 | "@ 96 | 97 | function Import-AksEdgeModule { 98 | if (Get-Command New-AksEdgeDeployment -ErrorAction SilentlyContinue) { return } 99 | # Load the modules 100 | $aksedgeShell = (Get-ChildItem -Path "$workdir" -Filter AksEdgeShell.ps1 -Recurse).FullName 101 | . $aksedgeShell 102 | } 103 | ### 104 | # Main 105 | ### 106 | if (-not (Test-Path -Path $installDir)) { 107 | Write-Host "Creating $installDir..." 108 | New-Item -Path "$installDir" -ItemType Directory | Out-Null 109 | } 110 | 111 | Set-ExecutionPolicy Bypass -Scope Process -Force 112 | # Download the AksEdgeDeploy modules from Azure/AksEdge 113 | 114 | $url = "https://github.com/Azure/AKS-Edge/archive/main.zip" 115 | $zipFile = "main-$starttimeString.zip" 116 | $workdir = "$installDir\AKS-Edge-main" 117 | if (-Not [string]::IsNullOrEmpty($Tag)) { 118 | $url = "https://github.com/Azure/AKS-Edge/archive/refs/tags/$Tag.zip" 119 | $zipFile = "$Tag.zip" 120 | $workdir = "$installDir\AKS-Edge-$tag" 121 | } 122 | 123 | $loop = $RunToComplete 124 | do { 125 | $step = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -ErrorAction SilentlyContinue 126 | 127 | if (!$step) { 128 | New-Item -Path HKLM:\SOFTWARE\AksEdgeScript | Out-Null 129 | New-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -PropertyType String -Value "CheckHyperV" | Out-Null 130 | $step = "CheckHyperV" 131 | } 132 | 133 | $errCode = 1 134 | switch ($step) { 135 | "CheckHyperV" { 136 | $starttime = Get-Date 137 | $transcriptFile = "$installDir\aksedgedlog-hyperv-$($starttime.ToString("yyMMdd-HHmm")).txt" 138 | Start-Transcript -Path $transcriptFile 139 | $feature = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V 140 | if ($feature.State -ne "Enabled") { 141 | Write-Host "Hyper-V is disabled" -ForegroundColor Red 142 | Write-Host "Enabling Hyper-V" 143 | Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All -NoRestart 144 | if ($aideSession.HostOS.IsServerSKU) { 145 | Enable-WindowsOptionalFeature -Online -FeatureName 'Microsoft-Hyper-V-Management-PowerShell' 146 | #Install-WindowsFeature -Name RSAT-Hyper-V-Tools -IncludeAllSubFeature 147 | } 148 | Write-Host "Reboot machine for enabling Hyper-V" -ForegroundColor Yellow 149 | $loop = $false 150 | $errCode = 2 151 | shutdown /r /t 30 152 | } else { 153 | Write-Host "Hyper-V is enabled" -ForegroundColor Green 154 | Set-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -Value "init" 155 | New-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name HyperVEnabled -PropertyType DWord -Value 1 -Force -ErrorAction SilentlyContinue | Out-Null 156 | } 157 | Stop-Transcript | Out-Null 158 | break; 159 | } 160 | "init" { # download bits 161 | $starttime = Get-Date 162 | $transcriptFile = "$installDir\aksedgedlog-init-$($starttime.ToString("yyMMdd-HHmm")).txt" 163 | Start-Transcript -Path $transcriptFile 164 | # Download the AksEdgeDeploy modules from Azure/AksEdge 165 | if (!(Test-Path -Path "$installDir\$zipFile")) { 166 | try { 167 | Invoke-WebRequest -Uri $url -OutFile $installDir\$zipFile -UseBasicParsing 168 | } catch { 169 | Write-Error -Message "Error: Downloading Aide Powershell Modules from $installDir\$zipFile failed" -Category OperationStopped 170 | Stop-Transcript | Out-Null 171 | exit -1 172 | } 173 | } 174 | Expand-Archive -Path $installDir\$zipFile -DestinationPath "$installDir" -Force 175 | $aidejson = (Get-ChildItem -Path "$workdir" -Filter aide-userconfig.json -Recurse).FullName 176 | Set-Content -Path $aidejson -Value $aideuserConfig -Force 177 | $aksedgejson = (Get-ChildItem -Path "$workdir" -Filter aksedge-config.json -Recurse).FullName 178 | Set-Content -Path $aksedgejson -Value $aksedgeConfig -Force 179 | Set-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -Value "DownloadDone" 180 | New-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name DownloadDone -PropertyType DWord -Value 1 | Out-Null 181 | $endtime = Get-Date 182 | $duration = ($endtime - $starttime) 183 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 184 | Stop-Transcript | Out-Null 185 | break; 186 | } 187 | "DownloadDone" { 188 | $starttime = Get-Date 189 | $transcriptFile = "$installDir\aksedgedlog-download-$($starttime.ToString("yyMMdd-HHmm")).txt" 190 | Start-Transcript -Path $transcriptFile 191 | Import-AksEdgeModule 192 | if (!(Test-AideMsiInstall -Install)) { 193 | Write-Error -Message "Error: Test-AideMsiInstall -Install failed" -Category OperationStopped 194 | Stop-Transcript | Out-Null 195 | exit -1 196 | } 197 | Set-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -Value "InstallDone" 198 | New-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallDone -PropertyType DWord -Value 1 | Out-Null 199 | $endtime = Get-Date 200 | $duration = ($endtime - $starttime) 201 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 202 | Stop-Transcript | Out-Null 203 | break; 204 | } 205 | "InstallDone" { 206 | $starttime = Get-Date 207 | $transcriptFile = "$installDir\aksedgedlog-install-$($starttime.ToString("yyMMdd-HHmm")).txt" 208 | Start-Transcript -Path $transcriptFile 209 | Import-AksEdgeModule 210 | Write-Host "Running Install-AksEdgeHostFeatures" -ForegroundColor Cyan 211 | if (!(Install-AksEdgeHostFeatures -Confirm:$false)) { 212 | Write-Error -Message "Error: Install-AksEdgeHostFeatures failed" -Category OperationStopped 213 | Stop-Transcript | Out-Null 214 | exit -1 215 | } 216 | if (Test-AideDeployment) { 217 | Write-Host "AKS edge VM is already deployed." -ForegroundColor Yellow 218 | } else { 219 | if (!(Test-AideVmSwitch -Create)) { 220 | Write-Error -Message "Error: Switch creation failed" -Category OperationStopped 221 | Stop-Transcript | Out-Null 222 | exit -1 223 | } #create switch if specified 224 | # We are here.. all is good so far. Validate and deploy aksedge 225 | if (!(Invoke-AideDeployment)) { 226 | Write-Error -Message "Error: Invoke-AideDeployment failed" -Category OperationStopped 227 | Stop-Transcript | Out-Null 228 | exit -1 229 | } 230 | } 231 | Set-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -Value "DeployDone" 232 | New-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name DeployDone -PropertyType DWord -Value 1 | Out-Null 233 | $endtime = Get-Date 234 | $duration = ($endtime - $starttime) 235 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 236 | Stop-Transcript | Out-Null 237 | break; 238 | } 239 | "DeployDone" { 240 | $starttime = Get-Date 241 | $transcriptFile = "$installDir\aksedgedlog-deploy-$($starttime.ToString("yyMMdd-HHmm")).txt" 242 | Start-Transcript -Path $transcriptFile 243 | Import-AksEdgeModule 244 | $status = Initialize-AideArc 245 | if ($status){ 246 | Write-Host "Connecting to Azure Arc" 247 | $retval = Connect-AideArc 248 | if ($retval) { 249 | Write-Host "Azure Arc connections successful." 250 | } else { 251 | Write-Error -Message "Azure Arc connections failed" -Category OperationStopped 252 | Stop-Transcript | Out-Null 253 | exit -1 254 | } 255 | } else { Write-Host "Error: Arc Initialization failed. Skipping Arc Connection" -ForegroundColor Red } 256 | Set-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name InstallStep -Value "AllDone" 257 | New-ItemProperty -Path HKLM:\SOFTWARE\AksEdgeScript -Name AllDone -PropertyType DWord -Value 1 | Out-Null 258 | $endtime = Get-Date 259 | $duration = ($endtime - $starttime) 260 | Write-Host "Duration: $($duration.Hours) hrs $($duration.Minutes) mins $($duration.Seconds) seconds" 261 | Stop-Transcript | Out-Null 262 | $errCode = 0 263 | $loop = $false 264 | break; 265 | } 266 | default { 267 | Write-Host "AKS edge is installed, deployed and connected to Arc" 268 | $errCode = 0 269 | $loop = $false 270 | break; 271 | } 272 | } 273 | } While ($loop) 274 | 275 | exit $errCode 276 | -------------------------------------------------------------------------------- /tools/modules/AksEdgeDeploy/AksEdgeDeploy-AEC.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | This module contains the Arc functions to use on Edge Essentials platforms (AksEdgeDeploy-Arc) 4 | #> 5 | #Requires -RunAsAdministrator 6 | if (! [Environment]::Is64BitProcess) { 7 | Write-Host "Error: Run this in 64bit Powershell session" -ForegroundColor Red 8 | exit -1 9 | } 10 | 11 | function Initialize-AideArc { 12 | <# 13 | .SYNOPSIS 14 | Checks and installs Azure CLI and validates the Azure configuration using the service principal credentials. 15 | 16 | .DESCRIPTION 17 | This command checks and installs Azure CLI by invoking Install-AideAzCli and validates the Azure configuration such as resource group, resource provider status using the service principal credentials.. 18 | 19 | .OUTPUTS 20 | Boolean 21 | True if all ok. 22 | 23 | .EXAMPLE 24 | Initialize-AideArc 25 | #> 26 | $status = Test-AideArcUserConfig 27 | if (!$status) { return $false } 28 | $aicfg = Get-AideArcUserConfig 29 | if (! $aicfg) { 30 | Write-Host "Error: UserConfig not set. Use Set-AideUserConfig to set" -Foreground Red 31 | return $false 32 | } 33 | Write-Host "Azure configuration:" 34 | Write-Host $aicfg 35 | $status = Test-ArcEdgeAzModules -Install 36 | if ($status) { 37 | Write-Host "Initialize-AideArc successful." -ForegroundColor Green 38 | } else { 39 | Write-Host "Initialize-AideArc failed." -ForegroundColor Red 40 | } 41 | return $status 42 | } 43 | 44 | function Enter-AideArcSession { 45 | <# 46 | .SYNOPSIS 47 | Logs into Azure using the service principal credentials supplied. 48 | 49 | .DESCRIPTION 50 | Logs into Azure using the service principal credentials supplied in the json file (Azure.Auth.ServicePrincipalId and Azure.Auth.Password). 51 | 52 | .OUTPUTS 53 | None 54 | 55 | .EXAMPLE 56 | Enter-AideArcSession 57 | #> 58 | $aicfg = Get-AideArcUserConfig 59 | $context = Get-AzContext 60 | if ($context) { 61 | Write-Host "Azure session active with $($context.Account)" 62 | return 63 | } 64 | if (!$context) { 65 | if (-not $aicfg.Auth) { 66 | Write-Host "Error: no valid credentials." -ForegroundColor Red 67 | return $false 68 | } 69 | $aiauth = $aicfg.Auth 70 | if ($aiauth.ServicePrincipalId) { 71 | Write-Host "Using service principal id to login" 72 | if ($aiauth.Password) { 73 | $secPwd = ConvertTo-SecureString -String $aiauth.Password -AsPlainText -Force 74 | $credential = New-Object System.Management.Automation.PSCredential($aiauth.ServicePrincipalId, $secPwd) 75 | $ret = Connect-AzAccount -Tenant $aicfg.TenantId -Subscription $aicfg.SubscriptionId -ServicePrincipal -Credential $Credential 76 | if (-not $ret) { 77 | Write-Host "Error: ServicePrincipalId/Password possibly expired." -ForegroundColor Red 78 | return $false 79 | } 80 | } else { 81 | Write-Host "Error: password not specified." -ForegroundColor Red 82 | return $false 83 | } 84 | } else { 85 | Write-Host "Error: no valid Auth parameters." -ForegroundColor Red 86 | return $false 87 | } 88 | } 89 | <# 90 | (az account set --subscription $aicfg.SubscriptionId) | Out-Null 91 | #az configure --defaults group=$aicfg.ResourceGroupName 92 | $session = (az account show | ConvertFrom-Json -ErrorAction SilentlyContinue) 93 | Write-Host "Logged in $($session.name) subscription as $($session.user.name) ($($session.user.type))" 94 | $roles = (az role assignment list --all --assignee $($session.user.name)) | ConvertFrom-Json 95 | if (-not $roles) { 96 | Write-Host "Error: No roles enabled for this account in this subscription" -ForegroundColor Red 97 | Exit-AideArcSession 98 | return $false 99 | } 100 | Write-Host "Roles enabled for this account are:" -ForegroundColor Cyan 101 | foreach ($role in $roles) { 102 | Write-Host "$($role.roleDefinitionName) for scope $($role.scope)" -ForegroundColor Cyan 103 | } 104 | $arciotSession.azSession = $session#> 105 | return $true 106 | } 107 | 108 | function Exit-AideArcSession { 109 | <# 110 | .SYNOPSIS 111 | Logs out of Azure session and clears account cache. 112 | 113 | .DESCRIPTION 114 | Logs out of Azure session and clears account cache. 115 | 116 | .OUTPUTS 117 | None 118 | 119 | .EXAMPLE 120 | Exit-AideArcSession 121 | #> 122 | #az logout 123 | #az account clear 124 | $context = Get-AzContext 125 | if ($context) { 126 | Write-Host "Azure session active with $($context.Account)" 127 | Disconnect-AzAccount # -ContextName $($context.Name) 128 | return 129 | } 130 | } 131 | 132 | ######################################### 133 | # Arc-enabled Kubernetes - Connected Clusters 134 | ######################################### 135 | 136 | function Get-AideArcClusterName { 137 | <# 138 | .SYNOPSIS 139 | Returns the cluster name for the deployed cluster. 140 | 141 | .DESCRIPTION 142 | This command returns the cluster name for the deployed cluster. If the user has specified Clustername in the aide-userconfig.json, the same is returned. 143 | If there is no user specifcation, it returns the clustername as hostname-k8s or hostname-k3s based on the kubernetes flavour installed. 144 | 145 | .OUTPUTS 146 | String 147 | 148 | .EXAMPLE 149 | Get-AideArcClusterName 150 | 151 | #> 152 | $aicfg = Get-AideArcUserConfig 153 | if ($aicfg.ClusterName) { 154 | $arciotSession.ClusterName = $aicfg.ClusterName 155 | } else { 156 | #$clustername = $(kubectl get configmap -n aksedge aksedge -o jsonpath="{.data.clustername}") 157 | #if (!$clustername){ 158 | $clustername = hostname 159 | $k3s = (kubectl get nodes) | Where-Object { $_ -match "k3s"} 160 | if ($k3s) { 161 | $clustername += "-k3s" 162 | } else { 163 | $clustername += "-k8s" 164 | } 165 | #} 166 | } 167 | return $clustername 168 | } 169 | 170 | function Test-AideArcKubernetes { 171 | return Test-AksEdgeArcConnection 172 | } 173 | 174 | function Get-AideArcKubernetesServiceToken { 175 | return Get-AksEdgeManagedServiceToken 176 | } 177 | 178 | function Connect-AideArc { 179 | <# 180 | .SYNOPSIS 181 | Connects the machine and the running kubernetes cluster to Azure Arc. 182 | 183 | .DESCRIPTION 184 | This command invokes Connect-AideArcServer which installs and connects Azure Arc Connected machine agent to Arc-enabled Server. 185 | Then it invokes Connect-AideArcKubernetes to connect the kubernetes cluster running on the machine (should be running control plane) to Arc-enabled Kubernetes. 186 | The inputs required are consumed from the aide-userconfig.json file. 187 | 188 | .OUTPUTS 189 | Boolean 190 | True if both the connection is successful and false if either one fails. 191 | 192 | .EXAMPLE 193 | Connect-AideArc 194 | 195 | #> 196 | 197 | Write-Host "Checking Azure Arc-enabled Kubernetes.." 198 | $kubernetesStatus = Test-AksEdgeArcConnection 199 | if ($kubernetesStatus) { 200 | Write-Host "-- Connection already exists." -ForegroundColor Yellow 201 | } else { 202 | Write-Host "Connecting Azure Arc-enabled Kubernetes.." 203 | $kubernetesStatus = Connect-AideArcKubernetes 204 | if ($kubernetesStatus) { 205 | Write-Host "-- Connection succeeded." -ForegroundColor Green 206 | } else { 207 | Write-Host "-- Connection failed." -ForegroundColor Red 208 | } 209 | } 210 | 211 | Write-Host "Connecting Azure Arc-enabled Server.." 212 | $serverStatus = Connect-AideArcServer 213 | if ($serverStatus) { 214 | Write-Host "-- Connection succeeded." -ForegroundColor Green 215 | } else { 216 | Write-Host "-- Connection failed." -ForegroundColor Red 217 | } 218 | 219 | return ($serverStatus -and $kubernetesStatus) 220 | } 221 | 222 | function Disconnect-AideArc { 223 | <# 224 | .SYNOPSIS 225 | Disconnects the machine and the running kubernetes cluster from Azure Arc. 226 | 227 | .DESCRIPTION 228 | This command invokes Disconnect-AideArcServer which disconnects from Arc-enabled Server, if connected. 229 | Then it invokes Disconnect-AideArcKubernetes to disconnect from Arc-enabled Kubernetes,if connected. 230 | The inputs required are consumed from the aide-userconfig.json file. 231 | 232 | .OUTPUTS 233 | Boolean 234 | True if both the disconnection is successful and false if either one fails. 235 | 236 | .EXAMPLE 237 | Disconnect-AideArc 238 | 239 | #> 240 | 241 | Write-Host "Disconnecting Azure Arc-enabled Kubernetes.." 242 | $kubernetesStatus = Disconnect-AideArcKubernetes 243 | if ($kubernetesStatus) { 244 | Write-Host "-- Disconnection succeeded." -ForegroundColor Green 245 | } else { 246 | Write-Host "-- Disconnection failed." -ForegroundColor Red 247 | } 248 | Write-Host "Disconnecting Azure Arc-enabled Server.." 249 | $serverStatus = Disconnect-AideArcServer 250 | if ($serverStatus) { 251 | Write-Host "-- Disconnection succeeded." -ForegroundColor Green 252 | } else { 253 | Write-Host "-- Disconnection failed." -ForegroundColor Red 254 | } 255 | return ($serverStatus -and $kubernetesStatus) 256 | } 257 | 258 | New-Variable -Option Constant -ErrorAction SilentlyContinue -Name arcEdgeInstallConfig -Value @{ 259 | "PSModules" = @( 260 | @{Name="Az.Resources"; Version="6.4.1"; Flags="-AllowClobber"}, 261 | @{Name="Az.Accounts"; Version="2.11.2"; Flags="-AllowClobber"}, 262 | @{Name="Az.ConnectedKubernetes"; Version="0.9.0"; Flags="-AllowClobber"} 263 | ) 264 | } 265 | function Test-ArcEdgeAzModules { 266 | Param 267 | ( 268 | [Switch] $Install 269 | ) 270 | $errCnt = 0 271 | 272 | $modules = Get-Module -ListAvailable 273 | 274 | #Install the required PowerShell modules 275 | $psgallery = Get-PSRepository | Where-Object { $_.Name -like "PSGallery" } 276 | if ($psgallery.InstallationPolicy -ine "Trusted") { 277 | # Do this always as by default PSGallery is untrusted. 278 | # See alternate means to force install rather than making this trusted. 279 | Write-Host "Setting PSGallery as Trusted Source" 280 | Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted 281 | } 282 | else { Write-Host "PSGallery is trusted" -ForegroundColor Green } 283 | 284 | $pkgproviders = Get-PackageProvider 285 | if ($pkgproviders.Name -notcontains "NuGet"){ 286 | Write-Host "Installing NuGet" 287 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false 288 | } else { Write-Host "NuGet found" -ForegroundColor Green } 289 | 290 | Write-Host "Checking Az Powershell modules....." 291 | $reqmods = $arcEdgeInstallConfig.PSModules 292 | foreach ($mod in $reqmods) { 293 | $module = $modules | Where-Object { $_.Name -like $mod.Name } 294 | if ($module ) { 295 | $installedVersion = $module.Version | Sort-Object -Descending | Select-Object -First 1 296 | if ((-not $mod.version) -or ([version]$installedVersion -ge [version]$mod.Version)) { 297 | Write-Host "* $($mod.Name) - $installedVersion found" -ForegroundColor Green 298 | continue 299 | } else { 300 | Write-Host "- $($mod.Name) - $installedVersion. Req: $($mod.Version)" 301 | $errCnt += 1 302 | } 303 | } else { 304 | Write-Host "- $($mod.Name) not found." 305 | $errCnt += 1 306 | } 307 | if ($Install) { 308 | Write-Host "Installing [$($mod.Name)-$($mod.Version) $($mod.Flags)].." 309 | $installcmd = "Install-Module -Name $($mod.Name)" 310 | if ($mod.Version -ine "") { 311 | $installcmd = $installcmd + " -RequiredVersion $($mod.Version)" 312 | } 313 | if ($mod.Flags -ine "") { 314 | $installcmd = $installcmd + " $($mod.Flags)" 315 | } 316 | Invoke-Expression -Command $installcmd 317 | $errCnt -= 1 318 | } 319 | } 320 | return ($errCnt -eq 0) 321 | } 322 | 323 | function Connect-AideArcKubernetes { 324 | $usrCfg = Get-AideUserConfig 325 | $json = ($usrCfg.AksEdgeConfig | ConvertTo-Json -Depth 6 ) 326 | $retVal = Connect-AksEdgeArc -JsonConfigString $json 327 | return ($retVal -eq "OK") 328 | } 329 | function Disconnect-AideArcKubernetes { 330 | $usrCfg = Get-AideUserConfig 331 | $json = ($usrCfg.AksEdgeConfig | ConvertTo-Json -Depth 6) 332 | $retVal = Disconnect-AksEdgeArc -JsonConfigString $json 333 | return ($retVal -eq "OK") 334 | } --------------------------------------------------------------------------------