Add vm-extension code
|
@ -0,0 +1,14 @@
|
|||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Use Node 8.x'
|
||||
inputs:
|
||||
versionSpec: 8.x
|
||||
|
||||
- task: Npm@1
|
||||
displayName: 'npm install'
|
||||
|
||||
- task: Npm@1
|
||||
displayName: 'Build'
|
||||
inputs:
|
||||
command: custom
|
||||
customCommand: run build
|
|
@ -0,0 +1,10 @@
|
|||
steps:
|
||||
- task: Npm@1
|
||||
displayName: 'Lint'
|
||||
inputs:
|
||||
command: custom
|
||||
customCommand: run lint
|
||||
|
||||
- task: ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
condition: ne(variables['System.PullRequest.IsFork'], 'True')
|
|
@ -0,0 +1,19 @@
|
|||
steps:
|
||||
- task: Npm@1
|
||||
displayName: 'Package'
|
||||
inputs:
|
||||
command: custom
|
||||
customCommand: run package
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy vsix to staging directory'
|
||||
inputs:
|
||||
Contents: '**/*.vsix'
|
||||
TargetFolder: '$(build.artifactstagingdirectory)'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish artifacts: vsix'
|
||||
inputs:
|
||||
PathtoPublish: '$(build.artifactstagingdirectory)'
|
||||
ArtifactName: vsix
|
||||
condition: ne(variables['System.PullRequest.IsFork'], 'True')
|
|
@ -0,0 +1,31 @@
|
|||
steps:
|
||||
- script: |
|
||||
sudo cp .azure-pipelines/linux/xvfb.init /etc/init.d/xvfb
|
||||
sudo chmod +x /etc/init.d/xvfb
|
||||
sudo update-rc.d xvfb defaults
|
||||
sudo service xvfb start
|
||||
displayName: 'Start X Virtual Frame Buffer'
|
||||
condition: eq(variables['Agent.OS'], 'Linux')
|
||||
|
||||
- task: UsePythonVersion@0
|
||||
displayName: 'Use Python 3.6.x'
|
||||
inputs:
|
||||
versionSpec: 3.6.x
|
||||
|
||||
- task: Npm@1
|
||||
displayName: 'Test'
|
||||
inputs:
|
||||
command: custom
|
||||
customCommand: test
|
||||
env:
|
||||
SERVICE_PRINCIPAL_CLIENT_ID: $(SERVICE_PRINCIPAL_CLIENT_ID)
|
||||
SERVICE_PRINCIPAL_SECRET: $(SERVICE_PRINCIPAL_SECRET)
|
||||
SERVICE_PRINCIPAL_DOMAIN: $(SERVICE_PRINCIPAL_DOMAIN)
|
||||
DISPLAY: :10 # Only necessary for linux tests
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
inputs:
|
||||
testResultsFiles: '*-results.xml'
|
||||
testRunTitle: '$(Agent.OS)'
|
||||
condition: succeededOrFailed()
|
|
@ -0,0 +1,56 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# COPIED FROM https://github.com/Microsoft/vscode/blob/e29c517386fe6f3a40e2f0ff00effae4919406aa/build/tfs/linux/x64/xvfb.init
|
||||
#
|
||||
#
|
||||
# /etc/rc.d/init.d/xvfbd
|
||||
#
|
||||
# chkconfig: 345 95 28
|
||||
# description: Starts/Stops X Virtual Framebuffer server
|
||||
# processname: Xvfb
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: xvfb
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start xvfb at boot time
|
||||
# Description: Enable xvfb provided by daemon.
|
||||
### END INIT INFO
|
||||
|
||||
[ "${NETWORKING}" = "no" ] && exit 0
|
||||
|
||||
PROG="/usr/bin/Xvfb"
|
||||
PROG_OPTIONS=":10 -ac"
|
||||
PROG_OUTPUT="/tmp/Xvfb.out"
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting : X Virtual Frame Buffer "
|
||||
$PROG $PROG_OPTIONS>>$PROG_OUTPUT 2>&1 &
|
||||
disown -ar
|
||||
;;
|
||||
stop)
|
||||
echo "Shutting down : X Virtual Frame Buffer"
|
||||
killproc $PROG
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && /bin/rm -f /var/lock/subsys/Xvfb
|
||||
/var/run/Xvfb.pid
|
||||
echo
|
||||
;;
|
||||
restart|reload)
|
||||
$0 stop
|
||||
$0 start
|
||||
RETVAL=$?
|
||||
;;
|
||||
status)
|
||||
status Xvfb
|
||||
RETVAL=$?
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 (start|stop|restart|reload|status)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
|
@ -0,0 +1,26 @@
|
|||
jobs:
|
||||
- job: Windows
|
||||
pool:
|
||||
vmImage: VS2017-Win2016
|
||||
steps:
|
||||
- template: common/build.yml
|
||||
- template: common/lint.yml
|
||||
- template: common/test.yml
|
||||
- template: windows/intellinav.yml
|
||||
|
||||
- job: Linux
|
||||
pool:
|
||||
vmImage: ubuntu-16.04
|
||||
steps:
|
||||
- template: common/build.yml
|
||||
- template: common/publish-vsix.yml # Only publish vsix from linux build since we use this to release and want to stay consistent
|
||||
- template: common/lint.yml
|
||||
- template: common/test.yml
|
||||
|
||||
- job: macOS
|
||||
pool:
|
||||
vmImage: macOS 10.13
|
||||
steps:
|
||||
- template: common/build.yml
|
||||
- template: common/lint.yml
|
||||
- template: common/test.yml
|
|
@ -0,0 +1,7 @@
|
|||
steps:
|
||||
- task: RichCodeNavIndexer@0
|
||||
inputs:
|
||||
serviceConnection: 'azuretools-dev' # name of the IntelliNav service connection
|
||||
languages: 'typescript' # languages in your repo, separated by commas
|
||||
githubServiceConnection: 'GitHub connection' # if your repo is on GitHub, this is the name of the GitHub service connection (GitHub organization by default)
|
||||
continueOnError: true
|
|
@ -0,0 +1 @@
|
|||
* @Microsoft/vscodeazuretools
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
daysAfterClose: 45,
|
||||
daysSinceLastUpdate: 7,
|
||||
perform: true
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
daysUntilClose: 21,
|
||||
needsMoreInfoLabel: 'needs more info',
|
||||
perform: true,
|
||||
closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/azcodeissuereporting) guidelines.\n\nHappy Coding!"
|
||||
}
|
|
@ -29,14 +29,14 @@ bower_components
|
|||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
|
@ -57,5 +57,15 @@ typings/
|
|||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
# Output
|
||||
out
|
||||
bin
|
||||
obj
|
||||
*.vsix
|
||||
.vscode-test
|
||||
test-results.xml
|
||||
dist
|
||||
stats.json
|
||||
|
||||
# debugging artifacts
|
||||
resources/dotnetTemplates
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"ms-vscode.azure-account"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: compile",
|
||||
"env": {
|
||||
"AZCODE_VIRTUALMACHINES_IGNORE_BUNDLE": "1",
|
||||
"DEBUGTELEMETRY": "1",
|
||||
"NODE_DEBUG": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Launch Extension (webpack)",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: webpack",
|
||||
"env": {
|
||||
"DEBUGTELEMETRY": "1",
|
||||
"NODE_DEBUG": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Launch Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test",
|
||||
"${workspaceFolder}/test/test.code-workspace"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: compile",
|
||||
"env": {
|
||||
"AZCODE_VIRTUALMACHINES_IGNORE_BUNDLE": "1",
|
||||
"MOCHA_grep": "", // RegExp of tests to run (empty for all)
|
||||
"MOCHA_enableTimeouts": "0", // Disable time-outs
|
||||
"DEBUGTELEMETRY": "1",
|
||||
"NODE_DEBUG": "",
|
||||
"ENABLE_LONG_RUNNING_TESTS": "",
|
||||
"FUNC_PATH": "func"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Launch Tests (webpack)",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/dist/test",
|
||||
"${workspaceFolder}/test/test.code-workspace"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: webpack",
|
||||
"env": {
|
||||
"MOCHA_grep": "", // RegExp of tests to run (empty for all)
|
||||
"MOCHA_enableTimeouts": "0", // Disable time-outs
|
||||
"DEBUGTELEMETRY": "1",
|
||||
"NODE_DEBUG": "",
|
||||
"ENABLE_LONG_RUNNING_TESTS": "",
|
||||
"FUNC_PATH": "func"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.tabSize": 4,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"search.exclude": {
|
||||
"out": true,
|
||||
"**/node_modules": true,
|
||||
".vscode-test": true,
|
||||
"resources/backup*Templates": true
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.tslint": true,
|
||||
},
|
||||
"tslint.ignoreDefinitionFiles": true,
|
||||
"files.exclude": {
|
||||
"tools/JsonCli/src/**": true
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": "relative"
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "compile",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"problemMatcher": "$tsc-watch"
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "lint",
|
||||
"problemMatcher": "$tslint5"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
.azure-pipelines/**
|
||||
.github/**
|
||||
.gitignore
|
||||
.vscode-test/**
|
||||
.vscode/**
|
||||
*.tgz
|
||||
**/*.gif
|
||||
**/*.map
|
||||
**/*.ts
|
||||
build/**
|
||||
dist/test/**
|
||||
docs/**
|
||||
gulp*
|
||||
node_modules/**
|
||||
out/**
|
||||
src/**
|
||||
stats.json
|
||||
test-results.xml
|
||||
test/**
|
||||
testOutput/**
|
||||
tools/**
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
typings/**
|
||||
webpack.config*
|
|
@ -0,0 +1,10 @@
|
|||
<!-- markdownlint-disable MD024 -->
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to the "azurevirtualmachines" extension will be documented in this file.
|
||||
|
||||
## 0.1.0 - 2019-10-22
|
||||
|
||||
### Added
|
||||
-
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
|
@ -0,0 +1,26 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* This is the external face of extension.bundle.js, the main webpack bundle for the extension.
|
||||
* Anything needing to be exposed outside of the extension sources must be exported from here, because
|
||||
* everything else will be in private modules in extension.bundle.js.
|
||||
*/
|
||||
|
||||
// Export activate/deactivate for main.js
|
||||
export { activateInternal, deactivateInternal } from './src/extension';
|
||||
|
||||
// Exports for tests
|
||||
// The tests are not packaged with the webpack bundle and therefore only have access to code exported from this file.
|
||||
//
|
||||
// The tests should import '../extension.bundle'. At design-time they live in tests/ and so will pick up this file (extension.bundle.ts).
|
||||
// At runtime the tests live in dist/tests and will therefore pick up the main webpack bundle at dist/extension.bundle.js.
|
||||
export * from './src/extensionVariables';
|
||||
export * from './src/vsCodeConfig/settings';
|
||||
export * from './src/tree/SubscriptionTreeItem';
|
||||
export * from './src/utils/delay';
|
||||
export * from './src/utils/cpUtils';
|
||||
export * from './src/vsCodeConfig/extensions';
|
||||
export * from 'vscode-azureextensionui';
|
|
@ -0,0 +1,29 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// tslint:disable:no-console
|
||||
// tslint:disable:no-implicit-dependencies (this allows the use of dev dependencies)
|
||||
|
||||
// Grandfathered in
|
||||
// tslint:disable:typedef
|
||||
// tslint:disable:no-unsafe-any
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import * as gulp from 'gulp';
|
||||
import * as path from 'path';
|
||||
import { gulp_installAzureAccount, gulp_webpack } from 'vscode-azureextensiondev';
|
||||
|
||||
function test() {
|
||||
const env = process.env;
|
||||
env.DEBUGTELEMETRY = '1';
|
||||
env.MOCHA_timeout = String(20 * 1000);
|
||||
env.CODE_TESTS_WORKSPACE = path.join(__dirname, 'test/test.code-workspace');
|
||||
env.CODE_TESTS_PATH = path.join(__dirname, 'dist/test');
|
||||
return cp.spawn('node', ['./node_modules/vscode/bin/test'], { stdio: 'inherit', env });
|
||||
}
|
||||
|
||||
exports['webpack-dev'] = () => gulp_webpack('development');
|
||||
exports['webpack-prod'] = () => gulp_webpack('production');
|
||||
exports.test = gulp.series(gulp_installAzureAccount, test);
|
|
@ -0,0 +1,35 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// This is the extension entrypoint module, which imports extension.bundle.js, the actual extension code.
|
||||
//
|
||||
// This is in a separate file so we can properly measure extension.bundle.js load time.
|
||||
|
||||
let perfStats = {
|
||||
loadStartTime: Date.now(),
|
||||
loadEndTime: undefined
|
||||
};
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const ignoreBundle = !/^(false|0)?$/i.test(process.env.AZCODE_VIRTUALMACHINES_IGNORE_BUNDLE || '');
|
||||
const extensionPath = ignoreBundle ? "./out/src/extension" : "./dist/extension.bundle";
|
||||
const extension = require(extensionPath);
|
||||
|
||||
async function activate(ctx) {
|
||||
return await extension.activateInternal(ctx, perfStats);
|
||||
}
|
||||
|
||||
async function deactivate(ctx) {
|
||||
return await extension.deactivateInternal(ctx, perfStats);
|
||||
}
|
||||
|
||||
// Export as entrypoints for vscode
|
||||
exports.activate = activate;
|
||||
exports.deactivate = deactivate;
|
||||
|
||||
perfStats.loadEndTime = Date.now();
|
|
@ -0,0 +1,229 @@
|
|||
{
|
||||
"name": "vscode-azurevirtualmachines",
|
||||
"displayName": "Azure Virtual Machines",
|
||||
"description": "%extension.description%",
|
||||
"version": "0.1.0-alpha",
|
||||
"publisher": "ms-azuretools",
|
||||
"icon": "resources/azure-vm.png",
|
||||
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
|
||||
"engines": {
|
||||
"vscode": "^1.31.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode-azurevirtualmachines"
|
||||
},
|
||||
"galleryBanner": {
|
||||
"color": "#0072c6",
|
||||
"theme": "dark"
|
||||
},
|
||||
"homepage": "https://github.com/Microsoft/vscode-azurevirtualmachines/blob/master/README.md",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"categories": [
|
||||
"Azure"
|
||||
],
|
||||
"keywords": [
|
||||
"Azure",
|
||||
"Virtual Machines",
|
||||
"Remote",
|
||||
"multi-root ready"
|
||||
],
|
||||
"preview": true,
|
||||
"activationEvents": [
|
||||
"onCommand:azureVirtualMachines.refresh",
|
||||
"onCommand:azureVirtualMachines.loadMore",
|
||||
"onCommand:azureVirtualMachines.openInPortal",
|
||||
"onView:azVmTree",
|
||||
"onDebugInitialConfigurations"
|
||||
],
|
||||
"main": "./main.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "azureVirtualMachines.selectSubscriptions",
|
||||
"title": "Select Subscriptions...",
|
||||
"icon": {
|
||||
"light": "resources/light/filter.svg",
|
||||
"dark": "resources/dark/filter.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.refresh",
|
||||
"title": "%azVms.refresh%",
|
||||
"category": "Azure Virtual Machines",
|
||||
"icon": {
|
||||
"light": "resources/light/Refresh.svg",
|
||||
"dark": "resources/dark/Refresh.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.loadMore",
|
||||
"title": "%azVms.loadMore%",
|
||||
"category": "Azure Virtual Machines"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.createVirtualMachine",
|
||||
"title": "Create Virtual Machine",
|
||||
"category": "Azure Virtual Machines"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.openInPortal",
|
||||
"title": "Open in Portal",
|
||||
"category": "Azure Virtual machines"
|
||||
}
|
||||
],
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "azure",
|
||||
"title": "Azure",
|
||||
"icon": "resources/azure.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"azure": [
|
||||
{
|
||||
"id": "azVmTree",
|
||||
"name": "Virtual Machines",
|
||||
"when": "config.azureVirtualMachines.showExplorer == true"
|
||||
}
|
||||
]
|
||||
},
|
||||
"menus": {
|
||||
"view/title": [
|
||||
{
|
||||
"command": "azureVirtualMachines.refresh",
|
||||
"when": "view == azVmTree",
|
||||
"group": "navigation@3"
|
||||
}
|
||||
],
|
||||
"view/item/context": [
|
||||
{
|
||||
"command": "azureVirtualMachines.selectSubscriptions",
|
||||
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.createVirtualMachine",
|
||||
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
|
||||
"group": "1@1"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.openInPortal",
|
||||
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
|
||||
"group": "2@1"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.refresh",
|
||||
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
|
||||
"group": "3@1"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.openInPortal",
|
||||
"when": "view == azVmTree && viewItem == azVmVirtualMachine",
|
||||
"group": "1@1"
|
||||
}
|
||||
],
|
||||
"explorer/context": [],
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "azureVirtualMachines.selectSubscriptions",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.refresh",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "azureVirtualMachines.loadMore",
|
||||
"when": "never"
|
||||
}
|
||||
],
|
||||
"editor/context": []
|
||||
},
|
||||
"jsonValidation": [],
|
||||
"taskDefinitions": [],
|
||||
"problemPatterns": [],
|
||||
"problemMatchers": [],
|
||||
"keybindings": [
|
||||
{
|
||||
"command": "workbench.view.extension.azure",
|
||||
"key": "ctrl+shift+a",
|
||||
"mac": "cmd+shift+a"
|
||||
}
|
||||
],
|
||||
"configuration": [
|
||||
{
|
||||
"title": "Azure Virtual Machines",
|
||||
"properties": {
|
||||
"azureVirtualMachines.showExplorer": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%azVms.showExplorerDescription%"
|
||||
},
|
||||
"azureVirtualMachines.templateFilter": {
|
||||
"scope": "resource",
|
||||
"type": "string",
|
||||
"default": "Verified",
|
||||
"enum": [
|
||||
"Verified",
|
||||
"Core",
|
||||
"All"
|
||||
],
|
||||
"description": "%azVms.templateFilterDescription%"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run webpack-prod",
|
||||
"build": "tsc -p ./",
|
||||
"compile": "tsc -watch -p ./",
|
||||
"package": "vsce package",
|
||||
"lint": "tslint --project tsconfig.json -e src/*.d.ts -t verbose",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||
"pretest": "npm run webpack-prod",
|
||||
"test": "gulp test",
|
||||
"webpack": "npm run build && gulp webpack-dev",
|
||||
"webpack-prod": "npm run build && gulp webpack-prod",
|
||||
"webpack-profile": "webpack --profile --json --mode production > webpack-stats.json && echo Use http://webpack.github.io/analyse to analyze the stats"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/gulp": "^4.0.6",
|
||||
"@types/gulp-filter": "^3.0.33",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@types/node": "^8.10.45",
|
||||
"@types/request": "2.0.7",
|
||||
"azure-arm-resource": "^3.0.0-preview",
|
||||
"copy-webpack-plugin": "^4.6.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-chmod": "^2.0.0",
|
||||
"gulp-decompress": "^2.0.1",
|
||||
"gulp-download": "^0.0.1",
|
||||
"gulp-filter": "^5.1.0",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-junit-reporter": "^1.18.0",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"ts-node": "^7.0.1",
|
||||
"tslint": "^5.14.0",
|
||||
"tslint-microsoft-contrib": "^5.2.1",
|
||||
"typescript": "^3.3.4000",
|
||||
"vsce": "^1.59.0",
|
||||
"vscode": "^1.1.33",
|
||||
"vscode-azureextensiondev": "0.2.3",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-cli": "^3.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"azure-arm-compute": "^10.0.0",
|
||||
"azure-arm-network": "^13.0.0",
|
||||
"semver": "^5.7.0",
|
||||
"vscode-azureextensionui": "^0.28.2",
|
||||
"vscode-nls": "^4.1.0"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
"ms-vscode.azure-account"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"extension.description": "An Azure Functions extension for Visual Studio Code.",
|
||||
"azVms.refresh": "Refresh",
|
||||
"azVms.loadMore": "Load More",
|
||||
"azVms.createNewProject": "Create New Project...",
|
||||
"azVms.initProjectForVSCode": "Initialize Project for Use with VS Code...",
|
||||
"azVms.createFunction": "Create Function...",
|
||||
"azVms.createFunctionApp": "Create Function App in Azure...",
|
||||
"azVms.openInPortal": "Open in Portal",
|
||||
"azVms.startFunctionApp": "Start",
|
||||
"azVms.stopFunctionApp": "Stop",
|
||||
"azVms.restartFunctionApp": "Restart",
|
||||
"azVms.deleteFunctionApp": "Delete Function App...",
|
||||
"azVms.copyFunctionUrl": "Copy Function Url",
|
||||
"azVms.executeFunction": "Execute Function Now",
|
||||
"azVms.deleteFunction": "Delete Function...",
|
||||
"azVms.showExplorerDescription": "Show or hide the Azure Functions Explorer",
|
||||
"azVms.templateFilterDescription": "Specify the templates to display when creating a new function. The supported values are 'Verified', 'Core', and 'All'. The 'Verified' category is a subset of 'Core' that has been verified to work with the latest VS Code extension.",
|
||||
"azVms.projectRuntimeDescription": "The default runtime to use when performing operations in the Azure Functions extension (e.g. \"Create New Function\").",
|
||||
"azVms.projectLanguageDescription": "The default language to use when performing operations in the Azure Functions extension (e.g. \"Create New Function\").",
|
||||
"azVms.deploy": "Deploy to Function App...",
|
||||
"azVms.configureDeploymentSource": "Configure Deployment Source...",
|
||||
"azVms.debugFunctionAppOnAzure": "Attach Debugger",
|
||||
"azVms.appSettings.add": "Add New Setting...",
|
||||
"azVms.appSettings.download": "Download Remote Settings...",
|
||||
"azVms.appSettings.upload": "Upload Local Settings...",
|
||||
"azVms.appSettings.edit": "Edit Setting...",
|
||||
"azVms.appSettings.rename": "Rename Setting...",
|
||||
"azVms.appSettings.delete": "Delete Setting...",
|
||||
"azVms.appSettings.decrypt": "Decrypt Settings",
|
||||
"azVms.appSettings.encrypt": "Encrypt Settings",
|
||||
"azVms.appSettings.toggleSlotSetting": "Toggle as Slot Setting",
|
||||
"azVms.pickProcess": "Pick Process",
|
||||
"azVms.deploySubpathDescription": "The default subpath of a workspace folder to use when deploying. If set, you will not be prompted for the folder path when deploying.",
|
||||
"azVms.projectSubpathDescription": "The default subpath of a workspace folder to use for project operations. This is only necessary if you have multiple projects in one workspace. See https://aka.ms/AA4nmfy for more information.",
|
||||
"azVms.showCoreToolsWarningDescription": "Show a warning if your installed version of Azure Functions Core Tools is out-of-date.",
|
||||
"azVms.showMultiCoreToolsWarningDescription": "Show a warning if multiple installs of Azure Functions Core Tools are detected.",
|
||||
"azVms.show64BitWarningDescription": "Show a warning to install a 64-bit version of the Azure Functions Core Tools when you create a .NET Framework project.",
|
||||
"azVms.showProjectWarningDescription": "Show a warning when an Azure Functions project was detected that has not been initialized for use in VS Code.",
|
||||
"azVms.showDebugConfigWarningDescription": "Show a warning when an Azure Functions project was detected that has an out-of-date debug configuration.",
|
||||
"azVms.showJavaDeployConfigWarningDescription": "Show a warning when an Azure Functions Java project was detected that has an out-of-date deploy configuration.",
|
||||
"azVms.showPythonVenvWarningDescription": "Show a warning when an Azure Functions Python project was detected that does not have a virtual environment.",
|
||||
"azVms.showTargetFrameworkWarningDescription": "Show a warning when an Azure Functions .NET project was detected that has mismatched target frameworks.",
|
||||
"azVms.showDeploySubpathWarningDescription": "Show a warning when the \"deploySubpath\" setting does not match the selected folder for deploying.",
|
||||
"azVms.startStreamingLogs": "Start Streaming Logs",
|
||||
"azVms.stopStreamingLogs": "Stop Streaming Logs",
|
||||
"azVms.enableRemoteDebugging": "Enable remote debugging, an experimental feature that only supports Java-based Functions Apps.",
|
||||
"azVms.deleteProxy": "Delete Proxy...",
|
||||
"azVms.pickProcessTimeoutDescription": "The timeout (in seconds) to be used when searching for the Azure Functions host process. Since a build is required every time you F5, you may need to adjust this based on how long your build takes.",
|
||||
"azVms.templateVersion": "A runtime release version (any runtime) that species which templates will be used rather than the latest templates. This version will be used for ALL runtimes. (Requires a restart of VS Code to take effect)",
|
||||
"azVms.projectOpenBehaviorDescription": "The behavior to use after creating a new project. The options are \"AddToWorkspace\", \"OpenInNewWindow\", or \"OpenInCurrentWindow\".",
|
||||
"azVms.uninstallFuncCoreTools": "Uninstall Azure Functions Core Tools",
|
||||
"azVms.installOrUpdateFuncCoreTools": "Install or Update Azure Functions Core Tools",
|
||||
"azVms.preDeployTaskDescription": "The name of the task to run before zip deployments.",
|
||||
"azVms.problemMatchers.funcWatch.label": "Azure Functions problems (watch mode)",
|
||||
"azVms.projectRuntime.v1Description": "Azure Functions v1 (.NET Framework)",
|
||||
"azVms.projectRuntime.v2Description": "Azure Functions v2 (.NET Standard)",
|
||||
"azVms.projectRuntime.betaDescription": "DEPRECATED Use \"~2\" instead.",
|
||||
"azVms.projectLanguage.previewDescription": "(Preview)",
|
||||
"azVms.pythonVenvDescription": "The name of the Python virtual environment used for your project. A virtual environment is required to debug and deploy Python functions.",
|
||||
"azVms.createPythonVenv": "Create a virtual environment when creating a new Python project.",
|
||||
"azVms.enableSlotsDescription": "Enable preview support for slots.",
|
||||
"azVms.redeploy": "Redeploy",
|
||||
"azVms.viewDeploymentLogs": "View Deployment Logs",
|
||||
"azVms.viewCommitInGitHub": "View Commit in GitHub",
|
||||
"azVms.ConnectToGitHub": "Connect to GitHub Repository...",
|
||||
"azVms.disconnectRepo": "Disconnect from Repo...",
|
||||
"azVms.createSlot": "Create Slot...",
|
||||
"azVms.swapSlot": "Swap Slot...",
|
||||
"azVms.advancedCreationDescription": "Enables advanced creation of Azure Function Apps, which will prompt for several additional values instead of using a default.",
|
||||
"azVms.toggleAppSettingVisibility": "Toggle App Setting Visibility.",
|
||||
"azVms.addBinding": "Add binding...",
|
||||
"azVms.setAzureWebJobsStorage": "Set AzureWebJobsStorage...",
|
||||
"azVms.enableProjectTree": "Enable preview support for a tree view of the local project."
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg viewBox="0 0 50 50" class="fxs-portal-svg" role="presentation" focusable="false" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="FxSymbol0-064"><g><title></title><path d="M31 38H19c1.634 5.768-.386 7-10 7v3h32v-3c-9.614 0-11.636-1.229-10-7z" class="msportalfx-svg-c04" fill="#7a7a7a"></path><path d="M46.979 2H2.717C1.213 2 0 3.325 0 4.805v30.412c0 1.471 1.213 2.782 2.717 2.782h44.262c1.501 0 3.021-1.31 3.021-2.782V4.805C50 3.321 48.48 2 46.979 2" class="msportalfx-svg-c03" fill="#a0a1a2"></path><path opacity=".2" d="M47.01 2.003l-.031-.002H2.716c-1.504 0-2.717 1.324-2.717 2.805v30.411C-.001 36.69 1.212 38 2.716 38h1.053L47.01 2.003z" class="msportalfx-svg-c01" fill="#ffffff"></path><path d="M46 6v28H4V6z" class="msportalfx-svg-c15" fill="#59b4d9"></path><path d="M9 44.979L41 45v3H9z" class="msportalfx-svg-c03" fill="#a0a1a2"></path><path d="M25.517 4.095a.71.71 0 1 1-1.42 0 .71.71 0 0 1 1.42 0" class="msportalfx-svg-c13" fill="#b8d432"></path><path d="M25.027 18.802a.271.271 0 0 1-.13-.036l-8.56-4.858a.257.257 0 0 1-.128-.221c0-.091.05-.175.128-.22l8.508-4.826a.265.265 0 0 1 .256 0l8.563 4.859a.25.25 0 0 1 .127.22.251.251 0 0 1-.127.22l-8.505 4.825a.274.274 0 0 1-.132.037" class="msportalfx-svg-c01" fill="#ffffff"></path><path opacity=".7" d="M23.797 30.608a.245.245 0 0 1-.13-.034l-8.534-4.842a.25.25 0 0 1-.133-.221v-9.717c0-.092.05-.175.132-.221a.26.26 0 0 1 .261 0l8.533 4.84a.265.265 0 0 1 .126.223v9.717a.26.26 0 0 1-.126.221.274.274 0 0 1-.129.034" class="msportalfx-svg-c01" fill="#ffffff"></path><path opacity=".4" d="M26.213 30.608a.28.28 0 0 1-.134-.034.257.257 0 0 1-.125-.221v-9.656c0-.09.05-.174.125-.221l8.533-4.84a.257.257 0 0 1 .257 0 .252.252 0 0 1 .131.22v9.655a.25.25 0 0 1-.131.221l-8.53 4.842a.236.236 0 0 1-.126.034" class="msportalfx-svg-c01" fill="#ffffff"></path><path d="M15 8H6v9h3v-6h6zM6 23v9h9v-3H9v-6zm29 9h9v-9h-3v6h-6zm9-15V8h-9v3h6v6z" class="msportalfx-svg-c01" fill="#ffffff"></path></g></svg>
|
После Ширина: | Высота: | Размер: 1.9 KiB |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="28" width="28" version="1.1" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path fill="#0072C6" d="M11.423,44.326l23.623-4.156L22.894,25.748l6.328-17.346L50,44.33L11.423,44.326z M27.566,5.67L11.469,40.109v-0.034H0l12.717-21.975L27.566,5.67z" />
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 337 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-action-green{fill:#89d185}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 1.414L11.414 6H16v1.414L7.414 16H5v-1.234L7.371 10H4V8.764L4.382 8H2.019V6H0V2.018h2.019V0H6v2.018h1.373L8.382 0H16v1.414z" id="outline" style="display: none;"/><path class="icon-vs-bg" d="M9 7h6l-8 8H6l2.984-6H5l.5-1H6V7l.5-1H8V3l1-2h6L9 7z" id="iconBg"/><path class="icon-vs-action-green" d="M7 3.018H5V1H3.019v2.018H1V5h2.019v2H5V5h2V3.018z" id="colorAction"/></svg>
|
После Ширина: | Высота: | Размер: 684 B |
|
@ -0,0 +1 @@
|
|||
<svg viewBox="0 0 50 50" class="fxs-portal-svg" role="presentation" focusable="false" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="FxSymbol0-064"><g><title></title><path d="M31 38H19c1.634 5.768-.386 7-10 7v3h32v-3c-9.614 0-11.636-1.229-10-7z" class="msportalfx-svg-c04" fill="#7a7a7a"></path><path d="M46.979 2H2.717C1.213 2 0 3.325 0 4.805v30.412c0 1.471 1.213 2.782 2.717 2.782h44.262c1.501 0 3.021-1.31 3.021-2.782V4.805C50 3.321 48.48 2 46.979 2" class="msportalfx-svg-c03" fill="#a0a1a2"></path><path opacity=".2" d="M47.01 2.003l-.031-.002H2.716c-1.504 0-2.717 1.324-2.717 2.805v30.411C-.001 36.69 1.212 38 2.716 38h1.053L47.01 2.003z" class="msportalfx-svg-c01" fill="#ffffff"></path><path d="M46 6v28H4V6z" class="msportalfx-svg-c15" fill="#59b4d9"></path><path d="M9 44.979L41 45v3H9z" class="msportalfx-svg-c03" fill="#a0a1a2"></path><path d="M25.517 4.095a.71.71 0 1 1-1.42 0 .71.71 0 0 1 1.42 0" class="msportalfx-svg-c13" fill="#b8d432"></path><path d="M25.027 18.802a.271.271 0 0 1-.13-.036l-8.56-4.858a.257.257 0 0 1-.128-.221c0-.091.05-.175.128-.22l8.508-4.826a.265.265 0 0 1 .256 0l8.563 4.859a.25.25 0 0 1 .127.22.251.251 0 0 1-.127.22l-8.505 4.825a.274.274 0 0 1-.132.037" class="msportalfx-svg-c01" fill="#ffffff"></path><path opacity=".7" d="M23.797 30.608a.245.245 0 0 1-.13-.034l-8.534-4.842a.25.25 0 0 1-.133-.221v-9.717c0-.092.05-.175.132-.221a.26.26 0 0 1 .261 0l8.533 4.84a.265.265 0 0 1 .126.223v9.717a.26.26 0 0 1-.126.221.274.274 0 0 1-.129.034" class="msportalfx-svg-c01" fill="#ffffff"></path><path opacity=".4" d="M26.213 30.608a.28.28 0 0 1-.134-.034.257.257 0 0 1-.125-.221v-9.656c0-.09.05-.174.125-.221l8.533-4.84a.257.257 0 0 1 .257 0 .252.252 0 0 1 .131.22v9.655a.25.25 0 0 1-.131.221l-8.53 4.842a.236.236 0 0 1-.126.034" class="msportalfx-svg-c01" fill="#ffffff"></path><path d="M15 8H6v9h3v-6h6zM6 23v9h9v-3H9v-6zm29 9h9v-9h-3v6h-6zm9-15V8h-9v3h6v6z" class="msportalfx-svg-c01" fill="#ffffff"></path></g></svg>
|
После Ширина: | Высота: | Размер: 1.9 KiB |
|
@ -0,0 +1,8 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="#e0e0e0" viewBox="0 0 24 24" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<rect x="8" y="4" width="13" height="2"/>
|
||||
<rect x="8" y="11" width="13" height="2"/>
|
||||
<rect x="8" y="18" width="13" height="2"/>
|
||||
<rect x="2" y="3" width="4" height="4"/>
|
||||
<rect x="2" y="10" width="4" height="4"/>
|
||||
<rect x="2" y="17" width="4" height="4"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 424 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-folder{fill:#c09553}.icon-vs-fg{fill:#2b282e}.icon-vs-bg{fill:#c5c5c5}</style><path class="icon-canvas-transparent" d="M0 0h16v16H0V0z" id="canvas"/><path class="icon-vs-out" d="M14.996 9.418V10H16v1.352l-1.004.96v.188c0 .827-.673 1.5-1.5 1.5h-.266l-2.092 2H9.441l.961-2H1.5C.673 14 0 13.327 0 12.5v-10C0 1.673.673 1 1.5 1h8.11l1 2h2.886c.827 0 1.5.673 1.5 1.5V7H16v1.414l-1.004 1.004z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M2 3h6.374l.5 1H2V3z" id="iconBg" style="display: none;"/><g id="iconFg"><path class="icon-vs-bg" d="M12 8l-2 4h2.5L11 15l4-4h-3l3-3z"/><path class="icon-folder" d="M13.996 7V4.5a.5.5 0 0 0-.5-.5H9.992l-1-2H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h6.882l3-6h2.614zM2 4V3h6.374l.5 1H2z"/></g></svg>
|
После Ширина: | Высота: | Размер: 894 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-action-blue{fill:#75beff}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M13 0v3H9.149l4.617 4.652-2.124 2.115L9 7.106V16H6V7.107L3.361 9.766 1.23 7.654 5.851 3H2V0h11z" id="outline" style="display: none;"/><g id="iconBg"><path class="icon-vs-action-blue" d="M3 1h9v1H3V1zm8.646 7.352l.708-.704L7.5 2.758l-4.855 4.89.71.704L7 4.681V15h1V4.681l3.646 3.671z"/></g></svg>
|
После Ширина: | Высота: | Размер: 580 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#252526}.icon-vs-out{fill:#252526}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2a292c}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M15 0v15H1V0h14z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M4 2v11h9V2H4zm7 3v1H6V4h5v1z" id="iconFg" style="display: none;"/><g id="iconBg"><path class="icon-vs-bg" d="M2 1v1h1v1H2v1h1v1H2v1h1v1H2v1h1v1H2v1h1v1H2v1h1v1H2v1h12V1H2zm11 12H4V2h9v11zm-2-9v2H6V4h5z"/></g></svg>
|
После Ширина: | Высота: | Размер: 599 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#2D2D30"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#C5C5C5"/></svg>
|
После Ширина: | Высота: | Размер: 986 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#252526;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#c5c5c5;}</style></defs><title>Visible_16x</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M16,9v1H11.444a3.965,3.965,0,0,1-6.888,0H0V9A8,8,0,0,1,16,9Z" style="display: none;"/></g><g id="iconBg"><path class="icon-vs-bg" d="M15,9H14A6,6,0,0,0,2,9H1A7,7,0,0,1,15,9ZM11,8A3,3,0,1,1,8,5,3,3,0,0,1,11,8ZM10,8a2,2,0,1,0-2,2A2,2,0,0,0,10,8Z"/></g></svg>
|
После Ширина: | Высота: | Размер: 629 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M0 0v3.043l5 6V16h6V9.043l5-6V0H0z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M7 14h2V8.319l5-6V2H2v.319l5 6V14z" id="iconFg" style="display: none;"/><path class="icon-vs-bg" d="M10 15H6V8.681l-5-6V1h14v1.681l-5 6V15zm-3-1h2V8.319l5-6V2H2v.319l5 6V14z" id="iconBg"/></svg>
|
После Ширина: | Высота: | Размер: 596 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-action-green{fill:#388a34}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 1.414L11.414 6H16v1.414L7.414 16H5v-1.234L7.371 10H4V8.764L4.382 8H2.019V6H0V2.018h2.019V0H6v2.018h1.373L8.382 0H16v1.414z" id="outline" style="display: none;"/><path class="icon-vs-bg" d="M9 7h6l-8 8H6l2.984-6H5l.5-1H6V7l.5-1H8V3l1-2h6L9 7z" id="iconBg"/><path class="icon-vs-action-green" d="M7 3.018H5V1H3.019v2.018H1V5h2.019v2H5V5h2V3.018z" id="colorAction"/></svg>
|
После Ширина: | Высота: | Размер: 684 B |
|
@ -0,0 +1 @@
|
|||
<svg viewBox="0 0 50 50" class="fxs-portal-svg" role="presentation" focusable="false" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="FxSymbol0-064"><g><title></title><path d="M31 38H19c1.634 5.768-.386 7-10 7v3h32v-3c-9.614 0-11.636-1.229-10-7z" class="msportalfx-svg-c04" fill="#7a7a7a"></path><path d="M46.979 2H2.717C1.213 2 0 3.325 0 4.805v30.412c0 1.471 1.213 2.782 2.717 2.782h44.262c1.501 0 3.021-1.31 3.021-2.782V4.805C50 3.321 48.48 2 46.979 2" class="msportalfx-svg-c03" fill="#a0a1a2"></path><path opacity=".2" d="M47.01 2.003l-.031-.002H2.716c-1.504 0-2.717 1.324-2.717 2.805v30.411C-.001 36.69 1.212 38 2.716 38h1.053L47.01 2.003z" class="msportalfx-svg-c01" fill="#ffffff"></path><path d="M46 6v28H4V6z" class="msportalfx-svg-c15" fill="#59b4d9"></path><path d="M9 44.979L41 45v3H9z" class="msportalfx-svg-c03" fill="#a0a1a2"></path><path d="M25.517 4.095a.71.71 0 1 1-1.42 0 .71.71 0 0 1 1.42 0" class="msportalfx-svg-c13" fill="#b8d432"></path><path d="M25.027 18.802a.271.271 0 0 1-.13-.036l-8.56-4.858a.257.257 0 0 1-.128-.221c0-.091.05-.175.128-.22l8.508-4.826a.265.265 0 0 1 .256 0l8.563 4.859a.25.25 0 0 1 .127.22.251.251 0 0 1-.127.22l-8.505 4.825a.274.274 0 0 1-.132.037" class="msportalfx-svg-c01" fill="#ffffff"></path><path opacity=".7" d="M23.797 30.608a.245.245 0 0 1-.13-.034l-8.534-4.842a.25.25 0 0 1-.133-.221v-9.717c0-.092.05-.175.132-.221a.26.26 0 0 1 .261 0l8.533 4.84a.265.265 0 0 1 .126.223v9.717a.26.26 0 0 1-.126.221.274.274 0 0 1-.129.034" class="msportalfx-svg-c01" fill="#ffffff"></path><path opacity=".4" d="M26.213 30.608a.28.28 0 0 1-.134-.034.257.257 0 0 1-.125-.221v-9.656c0-.09.05-.174.125-.221l8.533-4.84a.257.257 0 0 1 .257 0 .252.252 0 0 1 .131.22v9.655a.25.25 0 0 1-.131.221l-8.53 4.842a.236.236 0 0 1-.126.034" class="msportalfx-svg-c01" fill="#ffffff"></path><path d="M15 8H6v9h3v-6h6zM6 23v9h9v-3H9v-6zm29 9h9v-9h-3v6h-6zm9-15V8h-9v3h6v6z" class="msportalfx-svg-c01" fill="#ffffff"></path></g></svg>
|
После Ширина: | Высота: | Размер: 1.9 KiB |
|
@ -0,0 +1,8 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="#464f59" viewBox="0 0 24 24" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<rect x="8" y="4" width="13" height="2"/>
|
||||
<rect x="8" y="11" width="13" height="2"/>
|
||||
<rect x="8" y="18" width="13" height="2"/>
|
||||
<rect x="2" y="3" width="4" height="4"/>
|
||||
<rect x="2" y="10" width="4" height="4"/>
|
||||
<rect x="2" y="17" width="4" height="4"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 424 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-folder{fill:#dcb67a}.icon-vs-fg{fill:#f0eff1}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M0 0h16v16H0V0z" id="canvas"/><path class="icon-vs-out" d="M14.996 9.418V10H16v1.352l-1.004.96v.188c0 .827-.673 1.5-1.5 1.5h-.266l-2.092 2H9.441l.961-2H1.5C.673 14 0 13.327 0 12.5v-10C0 1.673.673 1 1.5 1h8.11l1 2h2.886c.827 0 1.5.673 1.5 1.5V7H16v1.414l-1.004 1.004z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M2 3h6.374l.5 1H2V3z" id="iconBg" style="display: none;"/><g id="iconFg"><path class="icon-vs-bg" d="M12 8l-2 4h2.5L11 15l4-4h-3l3-3z"/><path class="icon-folder" d="M13.996 7V4.5a.5.5 0 0 0-.5-.5H9.992l-1-2H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h6.882l3-6h2.614zM2 4V3h6.374l.5 1H2z"/></g></svg>
|
После Ширина: | Высота: | Размер: 894 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-action-blue{fill:#00539c}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M13 0v3H9.149l4.617 4.652-2.124 2.115L9 7.106V16H6V7.107L3.361 9.766 1.23 7.654 5.851 3H2V0h11z" id="outline" style="display: none;"/><g id="iconBg"><path class="icon-vs-action-blue" d="M3 1h9v1H3V1zm8.646 7.352l.708-.704L7.5 2.758l-4.855 4.89.71.704L7 4.681V15h1V4.681l3.646 3.671z"/></g></svg>
|
После Ширина: | Высота: | Размер: 580 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M15 0v15H1V0h14z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M4 2v11h9V2H4zm7 3v1H6V4h5v1z" id="iconFg" style="display: none;"/><g id="iconBg"><path class="icon-vs-bg" d="M2 1v1h1v1H2v1h1v1H2v1h1v1H2v1h1v1H2v1h1v1H2v1h1v1H2v1h12V1H2zm11 12H4V2h9v11zm-2-9v2H6V4h5z"/></g></svg>
|
После Ширина: | Высота: | Размер: 599 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#F6F6F6"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#424242"/></svg>
|
После Ширина: | Высота: | Размер: 986 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#424242;}</style></defs><title>Visible_16x</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M16,9v1H11.444a3.965,3.965,0,0,1-6.888,0H0V9A8,8,0,0,1,16,9Z" style="display: none;"/></g><g id="iconBg"><path class="icon-vs-bg" d="M15,9H14A6,6,0,0,0,2,9H1A7,7,0,0,1,15,9ZM11,8A3,3,0,1,1,8,5,3,3,0,0,1,11,8ZM10,8a2,2,0,1,0-2,2A2,2,0,0,0,10,8Z"/></g></svg>
|
После Ширина: | Высота: | Размер: 629 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M0 0v3.043l5 6V16h6V9.043l5-6V0H0z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M7 14h2V8.319l5-6V2H2v.319l5 6V14z" id="iconFg" style="display: none;"/><path class="icon-vs-bg" d="M10 15H6V8.681l-5-6V1h14v1.681l-5 6V15zm-3-1h2V8.319l5-6V2H2v.319l5 6V14z" id="iconBg"/></svg>
|
После Ширина: | Высота: | Размер: 596 B |
|
@ -0,0 +1,98 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ComputeManagementModels } from 'azure-arm-compute';
|
||||
import { NetworkManagementModels } from 'azure-arm-network';
|
||||
import { IResourceGroupWizardContext } from 'vscode-azureextensionui';
|
||||
|
||||
export interface IVirtualMachineWizardContext extends IResourceGroupWizardContext {
|
||||
/**
|
||||
* The newly created Virtual Machine
|
||||
* This will be defined after `VirtualMachineCreateStep.execute` occurs.
|
||||
*/
|
||||
virtualMachine?: ComputeManagementModels.VirtualMachine;
|
||||
|
||||
/**
|
||||
* The name of the new VM.
|
||||
* This will be defined after `VirtualMachineNameStep.prompt` occurs.
|
||||
*/
|
||||
newVirtualMachineName?: string;
|
||||
|
||||
/**
|
||||
* The hardware profile of the new VM. Specifies the size of the virtual machine.
|
||||
* This will be defined after `VirtualMachineNameStep.execute` occurs.
|
||||
*/
|
||||
hardwareProfile?: ComputeManagementModels.HardwareProfile;
|
||||
|
||||
/**
|
||||
* The size of the VM. The default value is `Standard_D2s_v3`.
|
||||
*/
|
||||
size?: string;
|
||||
|
||||
/**
|
||||
* The storage profile of the new VM. Specifies information about the image to use for the disk.
|
||||
* This will be defined after `VirtualMachineNameStep.execute` occurs.
|
||||
*/
|
||||
storageProfile?: ComputeManagementModels.StorageProfile;
|
||||
|
||||
/**
|
||||
* The image used to create the VM. The default is `Ubuntu Server 18.04 LTS`.
|
||||
*/
|
||||
image?: ComputeManagementModels.ImageReference;
|
||||
|
||||
/**
|
||||
* The network profile of the new VM. This is used to link the VM to a Network Interface.
|
||||
* This will be defined after `VirtualMachineNameStep.execute` occurs.
|
||||
*/
|
||||
networkProfile?: NetworkManagementModels.NetworkProfile;
|
||||
|
||||
/**
|
||||
* The network interface of the new VM. This contains all the ipConfigurations such as public IP and subnet
|
||||
* This will be defined after `NetworkInterfaceCreateStep.execute`
|
||||
*/
|
||||
networkInterface?: NetworkManagementModels.NetworkInterface;
|
||||
|
||||
/**
|
||||
* The name to use for the new network interface.
|
||||
* It is set to newVirtualMachineName123 by default, where 123 are random 0-9 digits.
|
||||
*/
|
||||
|
||||
newNetworkInterfaceName?: string;
|
||||
|
||||
/**
|
||||
* The network security group for the new VM. It contains the security rules that control opening ports for SSH/HTTP/HTTPS.
|
||||
* This will be defined after `NetworkSecurityGroupCreateStep.execute`
|
||||
*/
|
||||
networkSecurityGroup?: NetworkManagementModels.NetworkSecurityGroup;
|
||||
|
||||
/**
|
||||
* The public IP address for the new VM. This is the public IP address that the user connects to.
|
||||
* This will be defined after `PublicIpCreateStep.execute`
|
||||
*/
|
||||
publicIpAddress?: NetworkManagementModels.PublicIPAddress;
|
||||
|
||||
/**
|
||||
* The subnet for the new VM.
|
||||
* This will be defined after `SubnetCreateStep.execute`
|
||||
*/
|
||||
subnet?: NetworkManagementModels.Subnet;
|
||||
|
||||
/**
|
||||
* The virutal network for the new VM.
|
||||
* This will be defined after `VirtualNetworkCreateStep.execute`
|
||||
*/
|
||||
virtualNetwork?: NetworkManagementModels.VirtualNetwork;
|
||||
|
||||
/**
|
||||
* The username to connect to the VM via SSH. It defaults to `azureuser`
|
||||
*/
|
||||
adminUsername?: string;
|
||||
|
||||
/**
|
||||
* The addressPrefix that is used for subnets and virtual networks. It defaults to `10.1.0.0/24`.
|
||||
*/
|
||||
|
||||
addressPrefix?: string;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { NetworkManagementClient, NetworkManagementModels } from 'azure-arm-network';
|
||||
import { Progress } from "vscode";
|
||||
import { AzureWizardExecuteStep, createAzureClient } from "vscode-azureextensionui";
|
||||
import { localize } from '../../localize';
|
||||
import { nonNullProp, nonNullValueAndProp } from '../../utils/nonNull';
|
||||
import { IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';
|
||||
|
||||
export class NetworkInterfaceCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
|
||||
public priority: number = 250;
|
||||
|
||||
public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
const networkClient: NetworkManagementClient = createAzureClient(context, NetworkManagementClient);
|
||||
const location: string = nonNullValueAndProp(context.location, 'name');
|
||||
const vmName: string = nonNullProp(context, 'newVirtualMachineName');
|
||||
|
||||
// this is the naming convention used by the portal
|
||||
context.newNetworkInterfaceName = context.newNetworkInterfaceName || this.appendThreeRandomDigits(vmName);
|
||||
|
||||
const publicIpAddress: NetworkManagementModels.PublicIPAddress = nonNullProp(context, 'publicIpAddress');
|
||||
const subnet: NetworkManagementModels.Subnet = nonNullProp(context, 'subnet');
|
||||
|
||||
const networkInterfaceProps: NetworkManagementModels.NetworkInterface = {
|
||||
location, ipConfigurations: [{ name: context.newNetworkInterfaceName, publicIPAddress: publicIpAddress, subnet: subnet }]
|
||||
};
|
||||
|
||||
const creatingNi: string = localize('creatingNi', 'Creating network interface...');
|
||||
progress.report({ message: creatingNi });
|
||||
const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
|
||||
context.networkInterface = await networkClient.networkInterfaces.createOrUpdate(rgName, context.newNetworkInterfaceName, networkInterfaceProps);
|
||||
}
|
||||
public shouldExecute(context: IVirtualMachineWizardContext): boolean {
|
||||
return !context.networkInterface;
|
||||
}
|
||||
|
||||
private appendThreeRandomDigits(niName: string): string {
|
||||
for (let i: number = 0; i < 3; i += 1) {
|
||||
// as this isn't being used for security purposes, it should be sufficient to use Math.random()
|
||||
// tslint:disable-next-line: insecure-random
|
||||
niName += Math.round(Math.random() * 9);
|
||||
}
|
||||
|
||||
return niName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { NetworkManagementClient, NetworkManagementModels } from 'azure-arm-network';
|
||||
import { Progress } from "vscode";
|
||||
import { AzureWizardExecuteStep, createAzureClient } from "vscode-azureextensionui";
|
||||
import { localize } from '../../localize';
|
||||
import { nonNullProp, nonNullValueAndProp } from '../../utils/nonNull';
|
||||
import { IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';
|
||||
|
||||
export class NetworkSecurityGroupCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
|
||||
public priority: number = 250;
|
||||
|
||||
public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
const networkClient: NetworkManagementClient = createAzureClient(context, NetworkManagementClient);
|
||||
const location: string = nonNullValueAndProp(context.location, 'name');
|
||||
|
||||
// when creating a VM on the portal, this is the suffix that is added to the network security group
|
||||
const nsgName: string = nonNullProp(context, 'newVirtualMachineName') + '-nsg';
|
||||
const networkInterface: NetworkManagementModels.NetworkInterface = nonNullProp(context, 'networkInterface');
|
||||
|
||||
const networkSecurityGroupProps: NetworkManagementModels.NetworkSecurityGroup = {
|
||||
name: nsgName, location, securityRules: [
|
||||
{ name: 'SSH', protocol: 'TCP', sourcePortRange: '*', destinationPortRange: '22', sourceAddressPrefix: '*', destinationAddressPrefix: '*', access: 'Allow', priority: 340, direction: 'Inbound' },
|
||||
{ name: 'HTTPS', protocol: 'TCP', sourcePortRange: '*', destinationPortRange: '443', sourceAddressPrefix: '*', destinationAddressPrefix: '*', access: 'Allow', priority: 320, direction: 'Inbound' },
|
||||
{ name: 'HTTP', protocol: 'TCP', sourcePortRange: '*', destinationPortRange: '80', sourceAddressPrefix: '*', destinationAddressPrefix: '*', access: 'Allow', priority: 300, direction: 'Inbound' }
|
||||
],
|
||||
networkInterfaces: [networkInterface]
|
||||
};
|
||||
|
||||
const creatingNsg: string = localize('creatingNsg', 'Creating network security group...');
|
||||
const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
|
||||
progress.report({ message: creatingNsg });
|
||||
|
||||
context.networkSecurityGroup = await networkClient.networkSecurityGroups.createOrUpdate(rgName, nsgName, networkSecurityGroupProps);
|
||||
}
|
||||
public shouldExecute(context: IVirtualMachineWizardContext): boolean {
|
||||
return !context.networkSecurityGroup && !!context.location && !!context.newVirtualMachineName && !!context.networkInterface && !!context.resourceGroup;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { NetworkManagementClient, NetworkManagementModels } from 'azure-arm-network';
|
||||
import { Progress } from "vscode";
|
||||
import { AzureWizardExecuteStep, createAzureClient } from "vscode-azureextensionui";
|
||||
import { localize } from '../../localize';
|
||||
import { nonNullProp, nonNullValueAndProp } from '../../utils/nonNull';
|
||||
import { IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';
|
||||
|
||||
export class PublicIpCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
|
||||
public priority: number = 210;
|
||||
|
||||
public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
const networkClient: NetworkManagementClient = createAzureClient(context, NetworkManagementClient);
|
||||
|
||||
const location: string = nonNullValueAndProp(context.location, 'name');
|
||||
const publicIpProps: NetworkManagementModels.PublicIPAddress = { publicIPAddressVersion: 'IPv4', sku: { name: 'Standard' }, publicIPAllocationMethod: 'Static', location };
|
||||
|
||||
const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
|
||||
|
||||
// when creating a VM on the portal, this is the suffix that is added to the public IP address
|
||||
const ipName: string = nonNullProp(context, 'newVirtualMachineName') + '-ip';
|
||||
|
||||
const creatingIp: string = localize('creatingIp', 'Creating public IP addresss...');
|
||||
progress.report({ message: creatingIp });
|
||||
|
||||
context.publicIpAddress = await networkClient.publicIPAddresses.createOrUpdate(rgName, ipName, publicIpProps);
|
||||
}
|
||||
public shouldExecute(context: IVirtualMachineWizardContext): boolean {
|
||||
return !context.publicIpAddress;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { NetworkManagementClient, NetworkManagementModels } from 'azure-arm-network';
|
||||
import { Progress } from "vscode";
|
||||
import { AzureWizardExecuteStep, createAzureClient } from "vscode-azureextensionui";
|
||||
import { nonNullProp, nonNullValueAndProp } from '../../utils/nonNull';
|
||||
import { IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';
|
||||
|
||||
export class SubnetCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
|
||||
public priority: number = 230;
|
||||
|
||||
public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
const networkClient: NetworkManagementClient = createAzureClient(context, NetworkManagementClient);
|
||||
|
||||
const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
|
||||
const vnetName: string = nonNullValueAndProp(context.virtualNetwork, 'name');
|
||||
// this is the name the portal uses
|
||||
const subnetName: string = 'default';
|
||||
const subnetProps: NetworkManagementModels.Subnet = { addressPrefix: nonNullProp(context, 'addressPrefix'), name: subnetName };
|
||||
progress.report({ message: 'Creating subnet...' });
|
||||
|
||||
context.subnet = await networkClient.subnets.createOrUpdate(rgName, vnetName, subnetName, subnetProps);
|
||||
}
|
||||
public shouldExecute(context: IVirtualMachineWizardContext): boolean {
|
||||
return !context.subnet;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ComputeManagementClient, ComputeManagementModels } from 'azure-arm-compute';
|
||||
import { NetworkManagementModels } from 'azure-arm-network';
|
||||
import { Progress } from "vscode";
|
||||
import { AzureWizardExecuteStep, createAzureClient } from "vscode-azureextensionui";
|
||||
import { localize } from '../../localize';
|
||||
import { nonNullProp, nonNullValueAndProp } from '../../utils/nonNull';
|
||||
import { getSshKey } from "../getSshKey";
|
||||
import { IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';
|
||||
|
||||
export class VirtualMachineCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
|
||||
public priority: number = 260;
|
||||
|
||||
public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
const computeClient: ComputeManagementClient = createAzureClient(context, ComputeManagementClient);
|
||||
// tslint:disable-next-line: strict-boolean-expressions
|
||||
const hardwareProfile: ComputeManagementModels.HardwareProfile = { vmSize: context.size || 'Standard_D2s_v3' };
|
||||
|
||||
const vmName: string = nonNullProp(context, 'newVirtualMachineName');
|
||||
const storageProfile: ComputeManagementModels.StorageProfile = {
|
||||
// tslint:disable-next-line: strict-boolean-expressions
|
||||
imageReference: context.image || { offer: 'UbuntuServer', publisher: 'Canonical', sku: '18.04-LTS', version: 'latest' },
|
||||
osDisk: { name: vmName, createOption: 'fromImage', managedDisk: { storageAccountType: 'Premium_LRS' } }
|
||||
};
|
||||
|
||||
const networkInterface: NetworkManagementModels.NetworkInterface = nonNullProp(context, 'networkInterface');
|
||||
const networkProfile: ComputeManagementModels.NetworkProfile = { networkInterfaces: [{ id: networkInterface.id }] };
|
||||
|
||||
// tslint:disable-next-line: strict-boolean-expressions
|
||||
context.adminUsername = context.adminUsername || 'azureuser';
|
||||
|
||||
const linuxConfiguration: ComputeManagementModels.LinuxConfiguration = {
|
||||
disablePasswordAuthentication: true, ssh: {
|
||||
publicKeys: [{
|
||||
keyData: await getSshKey(),
|
||||
// because this is a Linux VM, use '/' as path separator rather than using path.join()
|
||||
path: `/home/${context.adminUsername}/.ssh/authorized_keys`
|
||||
}]
|
||||
}
|
||||
};
|
||||
const osProfile: ComputeManagementModels.OSProfile = { computerName: vmName, adminUsername: context.adminUsername, linuxConfiguration };
|
||||
|
||||
const location: string = nonNullValueAndProp(context.location, 'name');
|
||||
const virtualMachineProps: ComputeManagementModels.VirtualMachine = { location, hardwareProfile, storageProfile, networkProfile, osProfile };
|
||||
|
||||
const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
|
||||
|
||||
const creatingVm: string = localize('creatingVm', 'Creating virtual machine...');
|
||||
progress.report({ message: creatingVm });
|
||||
context.virtualMachine = await computeClient.virtualMachines.createOrUpdate(rgName, vmName, virtualMachineProps);
|
||||
}
|
||||
public shouldExecute(context: IVirtualMachineWizardContext): boolean {
|
||||
return !context.virtualMachine && !!context.newVirtualMachineName && !!context.networkInterface && !!context.location && !!context.resourceGroup;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ComputeManagementClient, ComputeManagementModels } from "azure-arm-compute";
|
||||
import { AzureNameStep, createAzureClient, IAzureNamingRules, resourceGroupNamingRules } from "vscode-azureextensionui";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { localize } from "../../localize";
|
||||
import { nonNullProp, nonNullValueAndProp } from "../../utils/nonNull";
|
||||
import { IVirtualMachineWizardContext } from "./IVirtualMachineWizardContext";
|
||||
|
||||
export const virtualMachineNamingRules: IAzureNamingRules = {
|
||||
minLength: 1,
|
||||
maxLength: 64,
|
||||
// cannot accept charactres that are invalid for Linux OS computername which is basically any non-alphanumeric except . and -
|
||||
invalidCharsRegExp: /[^a-zA-Z0-9\.\-]/
|
||||
};
|
||||
|
||||
export class VirtualMachineNameStep extends AzureNameStep<IVirtualMachineWizardContext> {
|
||||
public async prompt(wizardContext: IVirtualMachineWizardContext): Promise<void> {
|
||||
const namingRules: IAzureNamingRules[] = [resourceGroupNamingRules];
|
||||
namingRules.push(virtualMachineNamingRules);
|
||||
|
||||
const rgName: string = wizardContext.newResourceGroupName || nonNullValueAndProp(wizardContext.resourceGroup, 'name');
|
||||
const suggestedName: string | undefined = await this.generateRelatedName(wizardContext, rgName, namingRules);
|
||||
|
||||
const prompt: string = localize('virtualMachineNamePrompt', 'Enter a globally unique name for the new virutalMachine.');
|
||||
wizardContext.newVirtualMachineName = (await ext.ui.showInputBox({
|
||||
value: suggestedName,
|
||||
prompt,
|
||||
validateInput: async (value: string | undefined): Promise<string | undefined> => await this.validateVirtualMachineName(wizardContext, value)
|
||||
})).trim();
|
||||
}
|
||||
public shouldPrompt(wizardContext: IVirtualMachineWizardContext): boolean {
|
||||
return !wizardContext.newVirtualMachineName && !wizardContext.virtualMachine;
|
||||
}
|
||||
|
||||
protected async isRelatedNameAvailable(wizardContext: IVirtualMachineWizardContext, name: string): Promise<boolean> {
|
||||
return await this.isNameAvailable(wizardContext, name);
|
||||
}
|
||||
|
||||
private async validateVirtualMachineName(wizardContext: IVirtualMachineWizardContext, name: string | undefined): Promise<string | undefined> {
|
||||
name = name ? name.trim() : '';
|
||||
|
||||
if (name.length < virtualMachineNamingRules.minLength || name.length > virtualMachineNamingRules.maxLength) {
|
||||
return localize('invalidLength', 'The name must be between {0} and {1} characters.', virtualMachineNamingRules.minLength, virtualMachineNamingRules.maxLength);
|
||||
} else if (name.match(virtualMachineNamingRules.invalidCharsRegExp) !== null) {
|
||||
return localize('invalidChars', "The name can only contain alphanumeric characters and the symbols .-");
|
||||
} else if (name.endsWith('.') || name.endsWith('-')) {
|
||||
return localize('invalidEndingChar', "The name cannot end in a period or hyphen.");
|
||||
} else if (!await this.isNameAvailable(wizardContext, name)) {
|
||||
return localize('nameAlreadyExists', 'Virtual machine name "{0}" already exists in resource group "{1}".', name, nonNullValueAndProp(wizardContext.resourceGroup, 'name'));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async isNameAvailable(wizardContext: IVirtualMachineWizardContext, name: string): Promise<boolean> {
|
||||
// Virtual machine name must be unique in the current resource group.
|
||||
if (wizardContext.resourceGroup) {
|
||||
// only need to check if user used an existing resource group
|
||||
const computeClient: ComputeManagementClient = createAzureClient(wizardContext, ComputeManagementClient);
|
||||
const vmsInRg: ComputeManagementModels.VirtualMachineListResult = await computeClient.virtualMachines.list(nonNullProp(wizardContext.resourceGroup, 'name'));
|
||||
if (vmsInRg.find((vm: ComputeManagementModels.VirtualMachine) => vm.name === name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { NetworkManagementClient, NetworkManagementModels } from 'azure-arm-network';
|
||||
import { Progress } from "vscode";
|
||||
import { AzureWizardExecuteStep, createAzureClient } from "vscode-azureextensionui";
|
||||
import { nonNullProp, nonNullValueAndProp } from '../../utils/nonNull';
|
||||
import { IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';
|
||||
|
||||
export class VirtualNetworkCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
|
||||
public priority: number = 220;
|
||||
|
||||
public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
const networkClient: NetworkManagementClient = createAzureClient(context, NetworkManagementClient);
|
||||
const location: string = nonNullValueAndProp(context.location, 'name');
|
||||
|
||||
const virtualNetworkProps: NetworkManagementModels.VirtualNetwork = { location, addressSpace: { addressPrefixes: [nonNullProp(context, 'addressPrefix')] } };
|
||||
const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
|
||||
const vnName: string = nonNullProp(context, 'newVirtualMachineName') + '-vnet';
|
||||
|
||||
progress.report({ message: 'Creating virtual network...' });
|
||||
context.virtualNetwork = await networkClient.virtualNetworks.createOrUpdate(rgName, vnName, virtualNetworkProps);
|
||||
}
|
||||
public shouldExecute(context: IVirtualMachineWizardContext): boolean {
|
||||
return !context.virtualNetwork;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from "vscode-azureextensionui";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { SubscriptionTreeItem } from '../../tree/SubscriptionTreeItem';
|
||||
|
||||
export async function createVirtualMachine(context: IActionContext, node?: SubscriptionTreeItem | undefined): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.tree.showTreeItemPicker<SubscriptionTreeItem>(SubscriptionTreeItem.contextValue, context);
|
||||
}
|
||||
|
||||
await node.createChild(context);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from "os";
|
||||
import { Terminal, window } from "vscode";
|
||||
import { IParsedError, parseError } from "vscode-azureextensionui";
|
||||
import { cpUtils } from "../utils/cpUtils";
|
||||
import { delay } from "../utils/delay";
|
||||
|
||||
export async function getSshKey(): Promise<string> {
|
||||
try {
|
||||
return await cpUtils.executeCommand(undefined, undefined, 'cat ~/.ssh/id_rsa.pub');
|
||||
} catch (error) {
|
||||
const pError: IParsedError = parseError(error);
|
||||
if (pError.message.includes('No such file or directory')) {
|
||||
const sshKeygenTerminal: string = 'ssh-keygen';
|
||||
const sshKeygenCmd: string = 'ssh-keygen -t rsa -b 2048';
|
||||
// tslint:disable-next-line: strict-boolean-expressions
|
||||
const terminal: Terminal = window.terminals.find((activeTerminal: Terminal) => { return activeTerminal.name === sshKeygenTerminal; }) || window.createTerminal(sshKeygenTerminal);
|
||||
terminal.sendText(sshKeygenCmd, true);
|
||||
await delay(1000);
|
||||
// Enter file in which to save the key
|
||||
terminal.sendText(os.EOL, true);
|
||||
await delay(1000);
|
||||
//Enter passphrase (empty for no passphrase):
|
||||
terminal.sendText(os.EOL, true);
|
||||
await delay(1000);
|
||||
// Enter same passphrase again:
|
||||
terminal.sendText(os.EOL, true);
|
||||
|
||||
return await cpUtils.executeCommand(undefined, undefined, 'cat ~/.ssh/id_rsa.pub');
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzureTreeItem, IActionContext } from 'vscode-azureextensionui';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
|
||||
|
||||
export async function openInPortal(context: IActionContext, node?: AzureTreeItem): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.tree.showTreeItemPicker<AzureTreeItem>(VirtualMachineTreeItem.contextValue, context);
|
||||
}
|
||||
await node.openInPortal();
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { AzExtTreeDataProvider, AzureTreeItem, AzureUserInput, callWithTelemetryAndErrorHandling, createApiProvider, createAzExtOutputChannel, createTelemetryReporter, IActionContext, registerCommand, registerUIExtensionVariables } from 'vscode-azureextensionui';
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import { AzureExtensionApiProvider } from 'vscode-azureextensionui/api';
|
||||
import { createVirtualMachine } from './commands/createVirtualMachine/createVirtualMachine';
|
||||
import { openInPortal } from './commands/openInPortal';
|
||||
import { ext } from './extensionVariables';
|
||||
import { AzureAccountTreeItem } from './tree/AzureAccountTreeItem';
|
||||
import { SubscriptionTreeItem } from './tree/SubscriptionTreeItem';
|
||||
|
||||
export async function activateInternal(context: vscode.ExtensionContext, perfStats: { loadStartTime: number; loadEndTime: number }): Promise<AzureExtensionApiProvider> {
|
||||
ext.context = context;
|
||||
ext.reporter = createTelemetryReporter(context);
|
||||
ext.outputChannel = createAzExtOutputChannel('Azure Virtual Machines', ext.prefix);
|
||||
context.subscriptions.push(ext.outputChannel);
|
||||
ext.ui = new AzureUserInput(context.globalState);
|
||||
|
||||
registerUIExtensionVariables(ext);
|
||||
|
||||
await callWithTelemetryAndErrorHandling('azureVirtualMachines.activate', async (activateContext: IActionContext) => {
|
||||
activateContext.telemetry.properties.isActivationEvent = 'true';
|
||||
activateContext.telemetry.measurements.mainFileLoad = (perfStats.loadEndTime - perfStats.loadStartTime) / 1000;
|
||||
|
||||
ext.azureAccountTreeItem = new AzureAccountTreeItem();
|
||||
context.subscriptions.push(ext.azureAccountTreeItem);
|
||||
ext.tree = new AzExtTreeDataProvider(ext.azureAccountTreeItem, 'azureVirtualMachines.loadMore');
|
||||
context.subscriptions.push(vscode.window.createTreeView('azVmTree', { treeDataProvider: ext.tree }));
|
||||
|
||||
registerCommand('azureVirtualMachines.selectSubscriptions', () => vscode.commands.executeCommand('azure-account.selectSubscriptions'));
|
||||
registerCommand('azureVirtualMachines.refresh', async (_actionContext: IActionContext, node?: AzureTreeItem) => await ext.tree.refresh(node));
|
||||
registerCommand('azureVirtualMachines.loadMore', async (actionContext: IActionContext, node: AzureTreeItem) => await ext.tree.loadMore(node, actionContext));
|
||||
registerCommand('azureVirtualMachines.openInPortal', openInPortal);
|
||||
registerCommand('azureVirtualMachines.createVirtualMachine', async (actionContext: IActionContext, node?: SubscriptionTreeItem) => await createVirtualMachine(actionContext, node));
|
||||
});
|
||||
|
||||
return createApiProvider([]);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-empty
|
||||
export function deactivateInternal(): void {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionContext, TreeView } from "vscode";
|
||||
import { AzExtTreeDataProvider, AzExtTreeItem, IAzExtOutputChannel, IAzureUserInput, ITelemetryReporter } from "vscode-azureextensionui";
|
||||
import { AzureAccountTreeItem } from "./tree/AzureAccountTreeItem";
|
||||
|
||||
/**
|
||||
* Namespace for common variables used throughout the extension. They must be initialized in the activate() method of extension.ts
|
||||
*/
|
||||
export namespace ext {
|
||||
export let outputChannel: IAzExtOutputChannel;
|
||||
export let ui: IAzureUserInput;
|
||||
export let reporter: ITelemetryReporter;
|
||||
export let context: ExtensionContext;
|
||||
|
||||
export let tree: AzExtTreeDataProvider;
|
||||
export let treeView: TreeView<AzExtTreeItem>;
|
||||
export let azureAccountTreeItem: AzureAccountTreeItem;
|
||||
export const prefix: string = 'azureVirtualMachines';
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
export const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
|
@ -0,0 +1,17 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzureAccountTreeItemBase, ISubscriptionContext } from 'vscode-azureextensionui';
|
||||
import { SubscriptionTreeItem } from './SubscriptionTreeItem';
|
||||
|
||||
export class AzureAccountTreeItem extends AzureAccountTreeItemBase {
|
||||
public constructor(testAccount?: {}) {
|
||||
super(undefined, testAccount);
|
||||
}
|
||||
|
||||
public createSubscriptionTreeItem(root: ISubscriptionContext): SubscriptionTreeItem {
|
||||
return new SubscriptionTreeItem(this, root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ComputeManagementClient, ComputeManagementModels } from 'azure-arm-compute';
|
||||
import { AzExtTreeItem, AzureTreeItem, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, createAzureClient, ICreateChildImplContext, LocationListStep, parseError, ResourceGroupListStep, SubscriptionTreeItemBase } from 'vscode-azureextensionui';
|
||||
import { IVirtualMachineWizardContext } from '../commands/createVirtualMachine/IVirtualMachineWizardContext';
|
||||
import { NetworkInterfaceCreateStep } from '../commands/createVirtualMachine/NetworkInterfaceCreateStep';
|
||||
import { NetworkSecurityGroupCreateStep } from '../commands/createVirtualMachine/NetworkSecurityGroupCreateStep';
|
||||
import { PublicIpCreateStep } from '../commands/createVirtualMachine/PublicIpCreateStep';
|
||||
import { SubnetCreateStep } from '../commands/createVirtualMachine/SubnetCreateStep';
|
||||
import { VirtualMachineCreateStep } from '../commands/createVirtualMachine/VirtualMachineCreateStep';
|
||||
import { VirtualMachineNameStep } from '../commands/createVirtualMachine/VirtualMachineNameStep';
|
||||
import { VirtualNetworkCreateStep } from '../commands/createVirtualMachine/VirtualNetworkCreateStep';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { nonNullProp } from '../utils/nonNull';
|
||||
import { VirtualMachineTreeItem } from './VirtualMachineTreeItem';
|
||||
|
||||
export class SubscriptionTreeItem extends SubscriptionTreeItemBase {
|
||||
public readonly childTypeLabel: string = 'azVmVirtualMachine';
|
||||
|
||||
private _nextLink: string | undefined;
|
||||
|
||||
public hasMoreChildrenImpl(): boolean {
|
||||
return this._nextLink !== undefined;
|
||||
}
|
||||
|
||||
public async loadMoreChildrenImpl(clearCache: boolean): Promise<AzExtTreeItem[]> {
|
||||
if (clearCache) {
|
||||
this._nextLink = undefined;
|
||||
}
|
||||
|
||||
const client: ComputeManagementClient = createAzureClient(this.root, ComputeManagementClient);
|
||||
let virtualMachines: ComputeManagementModels.VirtualMachineListResult;
|
||||
|
||||
try {
|
||||
virtualMachines = this._nextLink === undefined ?
|
||||
await client.virtualMachines.listAll() :
|
||||
await client.virtualMachines.listNext(this._nextLink);
|
||||
} catch (error) {
|
||||
if (parseError(error).errorType.toLowerCase() === 'notfound') {
|
||||
// This error type means the 'Microsoft.Web' provider has not been registered in this subscription
|
||||
// In that case, we know there are no web apps, so we can return an empty array
|
||||
// (The provider will be registered automatically if the user creates a new web app)
|
||||
return [];
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this._nextLink = virtualMachines.nextLink;
|
||||
|
||||
return await this.createTreeItemsWithErrorHandling(
|
||||
virtualMachines,
|
||||
'invalidVirtualMachine',
|
||||
(vm: ComputeManagementModels.VirtualMachine) => {
|
||||
return new VirtualMachineTreeItem(this, vm);
|
||||
},
|
||||
(vm: ComputeManagementModels.VirtualMachine) => {
|
||||
return vm.name;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async createChildImpl(context: ICreateChildImplContext): Promise<AzureTreeItem> {
|
||||
const wizardContext: IVirtualMachineWizardContext = Object.assign(context, this.root, {
|
||||
resourceGroupDeferLocationStep: true,
|
||||
addressPrefix: '10.1.0.0/24'
|
||||
});
|
||||
|
||||
// prompt for resourceGroup, VM name, and location
|
||||
const promptSteps: AzureWizardPromptStep<IVirtualMachineWizardContext>[] = [];
|
||||
promptSteps.push(new ResourceGroupListStep());
|
||||
promptSteps.push(new VirtualMachineNameStep());
|
||||
LocationListStep.addStep(wizardContext, promptSteps);
|
||||
|
||||
// create a disk, publicIp, virtualNetwork, subnet, networkInterface, networkSecurityGroup (this has the security rules), and then virtuaMachine
|
||||
const executeSteps: AzureWizardExecuteStep<IVirtualMachineWizardContext>[] = [];
|
||||
// executeSteps.push(new DiskCreateStep());
|
||||
executeSteps.push(new PublicIpCreateStep());
|
||||
executeSteps.push(new VirtualNetworkCreateStep());
|
||||
executeSteps.push(new SubnetCreateStep());
|
||||
executeSteps.push(new NetworkInterfaceCreateStep());
|
||||
executeSteps.push(new NetworkSecurityGroupCreateStep());
|
||||
executeSteps.push(new VirtualMachineCreateStep());
|
||||
|
||||
const title: string = 'Create new virtual machine';
|
||||
const wizard: AzureWizard<IVirtualMachineWizardContext> = new AzureWizard(wizardContext, { promptSteps, executeSteps, title });
|
||||
|
||||
await wizard.prompt();
|
||||
|
||||
context.showCreatingTreeItem(nonNullProp(wizardContext, 'newVirtualMachineName'));
|
||||
|
||||
await wizard.execute();
|
||||
|
||||
const virtualMachine: ComputeManagementModels.VirtualMachine = nonNullProp(wizardContext, 'virtualMachine');
|
||||
// context.telemetry.properties.vm = virtualMachine.name;
|
||||
|
||||
const createNewVmMsg: string = `Created new virtual machine "${virtualMachine.name}".`;
|
||||
ext.outputChannel.appendLine(createNewVmMsg);
|
||||
|
||||
return new VirtualMachineTreeItem(this, virtualMachine);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ComputeManagementModels } from 'azure-arm-compute';
|
||||
import NetworkManagementClient, { NetworkManagementModels } from 'azure-arm-network';
|
||||
import { env } from 'vscode';
|
||||
import { AzureParentTreeItem, AzureTreeItem, createAzureClient } from 'vscode-azureextensionui';
|
||||
import { localize } from '../localize';
|
||||
import { getNameFromId, getResourceGroupFromId } from '../utils/azureUtils';
|
||||
import { nonNullProp, nonNullValueAndProp } from '../utils/nonNull';
|
||||
import { treeUtils } from '../utils/treeUtils';
|
||||
|
||||
export class VirtualMachineTreeItem extends AzureTreeItem {
|
||||
public get label(): string {
|
||||
return `${getResourceGroupFromId(this.id).toLocaleLowerCase()}/${nonNullProp(this.virtualMachine, 'name')}`;
|
||||
}
|
||||
|
||||
public get iconPath(): treeUtils.IThemedIconPath {
|
||||
return treeUtils.getThemedIconPath('AzureVm');
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return nonNullProp(this.virtualMachine, 'id');
|
||||
}
|
||||
|
||||
public static contextValue: string = 'azVmVirtualMachine';
|
||||
public readonly contextValue: string = VirtualMachineTreeItem.contextValue;
|
||||
public virtualMachine: ComputeManagementModels.VirtualMachine;
|
||||
public constructor(parent: AzureParentTreeItem, vm: ComputeManagementModels.VirtualMachine) {
|
||||
super(parent);
|
||||
this.virtualMachine = vm;
|
||||
}
|
||||
|
||||
public async getHostname(): Promise<string> {
|
||||
const networkClient: NetworkManagementClient = createAzureClient(this.root, NetworkManagementClient);
|
||||
const rgName: string = getResourceGroupFromId(this.id);
|
||||
|
||||
const networkInterfaces: ComputeManagementModels.NetworkInterfaceReference[] = nonNullValueAndProp(this.virtualMachine.networkProfile, 'networkInterfaces');
|
||||
if (networkInterfaces.length === 0) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const networkInterfaceName: string = getNameFromId(nonNullProp(networkInterfaces[0], 'id'));
|
||||
const networkInterface: NetworkManagementModels.NetworkInterface = await networkClient.networkInterfaces.get(rgName, networkInterfaceName);
|
||||
|
||||
if (!networkInterface.ipConfigurations || networkInterface.ipConfigurations.length === 0) {
|
||||
const noIpConfigs: string = localize('noIpConfigs', 'No IP configurations are associated with network interface "{0}"', networkInterface.name);
|
||||
throw new Error(noIpConfigs);
|
||||
}
|
||||
|
||||
const publicIPAddressName: string = getNameFromId(nonNullValueAndProp(networkInterface.ipConfigurations[0].publicIPAddress, 'id'));
|
||||
const ip: NetworkManagementModels.PublicIPAddress = await networkClient.publicIPAddresses.get(rgName, publicIPAddressName);
|
||||
const hostname: string = `${nonNullValueAndProp(this.virtualMachine.osProfile, 'adminUsername')}@${nonNullProp(ip, 'ipAddress')}`;
|
||||
|
||||
await env.clipboard.writeText(hostname);
|
||||
return hostname;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from '../localize';
|
||||
|
||||
function parseResourceId(id: string): RegExpMatchArray {
|
||||
const matches: RegExpMatchArray | null = id.match(/\/subscriptions\/(.*)\/resourceGroups\/(.*)\/providers\/(.*)\/(.*)/);
|
||||
|
||||
if (matches === null || matches.length < 3) {
|
||||
throw new Error(localize('InvalidResourceId', 'Invalid Azure Resource Id'));
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
export function getResourceGroupFromId(id: string): string {
|
||||
return parseResourceId(id)[2];
|
||||
}
|
||||
|
||||
export function getSubscriptionFromId(id: string): string {
|
||||
return parseResourceId(id)[1];
|
||||
}
|
||||
|
||||
export function getNameFromId(id: string): string {
|
||||
return parseResourceId(id)[4];
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import * as os from 'os';
|
||||
import * as vscode from 'vscode';
|
||||
import { localize } from '../localize';
|
||||
|
||||
export namespace cpUtils {
|
||||
export async function executeCommand(outputChannel: vscode.OutputChannel | undefined, workingDirectory: string | undefined, command: string, ...args: string[]): Promise<string> {
|
||||
const result: ICommandResult = await tryExecuteCommand(outputChannel, workingDirectory, command, ...args);
|
||||
if (result.code !== 0) {
|
||||
// We want to make sure the full error message is displayed to the user, not just the error code.
|
||||
// If outputChannel is defined, then we simply call 'outputChannel.show()' and throw a generic error telling the user to check the output window
|
||||
// If outputChannel is _not_ defined, then we include the command's output in the error itself and rely on AzureActionHandler to display it properly
|
||||
if (outputChannel) {
|
||||
outputChannel.show();
|
||||
throw new Error(localize('azVms.commandErrorWithOutput', 'Failed to run "{0}" command. Check output window for more details.', command));
|
||||
} else {
|
||||
throw new Error(localize('azVms.commandError', 'Command "{0} {1}" failed with exit code "{2}":{3}{4}', command, result.formattedArgs, result.code, os.EOL, result.cmdOutputIncludingStderr));
|
||||
}
|
||||
} else {
|
||||
if (outputChannel) {
|
||||
outputChannel.appendLine(localize('finishedRunningCommand', 'Finished running command: "{0} {1}".', command, result.formattedArgs));
|
||||
}
|
||||
}
|
||||
return result.cmdOutput;
|
||||
}
|
||||
|
||||
export async function tryExecuteCommand(outputChannel: vscode.OutputChannel | undefined, workingDirectory: string | undefined, command: string, ...args: string[]): Promise<ICommandResult> {
|
||||
return await new Promise((resolve: (res: ICommandResult) => void, reject: (e: Error) => void): void => {
|
||||
let cmdOutput: string = '';
|
||||
let cmdOutputIncludingStderr: string = '';
|
||||
const formattedArgs: string = args.join(' ');
|
||||
|
||||
workingDirectory = workingDirectory || os.tmpdir();
|
||||
const options: cp.SpawnOptions = {
|
||||
cwd: workingDirectory,
|
||||
shell: true
|
||||
};
|
||||
const childProc: cp.ChildProcess = cp.spawn(command, args, options);
|
||||
|
||||
if (outputChannel) {
|
||||
outputChannel.appendLine(localize('runningCommand', 'Running command: "{0} {1}"...', command, formattedArgs));
|
||||
}
|
||||
|
||||
childProc.stdout.on('data', (data: string | Buffer) => {
|
||||
data = data.toString();
|
||||
cmdOutput = cmdOutput.concat(data);
|
||||
cmdOutputIncludingStderr = cmdOutputIncludingStderr.concat(data);
|
||||
if (outputChannel) {
|
||||
outputChannel.append(data);
|
||||
}
|
||||
});
|
||||
|
||||
childProc.stderr.on('data', (data: string | Buffer) => {
|
||||
data = data.toString();
|
||||
cmdOutputIncludingStderr = cmdOutputIncludingStderr.concat(data);
|
||||
if (outputChannel) {
|
||||
outputChannel.append(data);
|
||||
}
|
||||
});
|
||||
|
||||
childProc.on('error', reject);
|
||||
childProc.on('close', (code: number) => {
|
||||
resolve({
|
||||
code,
|
||||
cmdOutput,
|
||||
cmdOutputIncludingStderr,
|
||||
formattedArgs
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export interface ICommandResult {
|
||||
code: number;
|
||||
cmdOutput: string;
|
||||
cmdOutputIncludingStderr: string;
|
||||
formattedArgs: string;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export async function delay(ms: number): Promise<void> {
|
||||
await new Promise<void>((resolve: () => void): NodeJS.Timer => setTimeout(resolve, ms));
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* Returns a node module installed with VSCode, or undefined if it fails.
|
||||
*/
|
||||
export function getCoreNodeModule<T>(moduleName: string): T | undefined {
|
||||
try {
|
||||
// tslint:disable-next-line:non-literal-require no-unsafe-any
|
||||
return require(`${vscode.env.appRoot}/node_modules.asar/${moduleName}`);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable-next-line:non-literal-require no-unsafe-any
|
||||
return require(`${vscode.env.appRoot}/node_modules/${moduleName}`);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
return undefined;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isNullOrUndefined } from 'util';
|
||||
|
||||
/**
|
||||
* Retrieves a property by name from an object and checks that it's not null and not undefined. It is strongly typed
|
||||
* for the property and will give a compile error if the given name is not a property of the source.
|
||||
*/
|
||||
export function nonNullProp<TSource, TKey extends keyof TSource>(source: TSource, name: TKey): NonNullable<TSource[TKey]> {
|
||||
const value: NonNullable<TSource[TKey]> = <NonNullable<TSource[TKey]>>source[name];
|
||||
return nonNullValue(value, <string>name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a given value is not null and not undefined.
|
||||
*/
|
||||
export function nonNullValue<T>(value: T | undefined | null, propertyNameOrMessage?: string): T {
|
||||
if (isNullOrUndefined(value)) {
|
||||
throw new Error(
|
||||
// tslint:disable-next-line:prefer-template
|
||||
'Internal error: Expected value to be neither null nor undefined'
|
||||
+ (propertyNameOrMessage ? `: ${propertyNameOrMessage}` : ''));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a given object is not null and not undefined.
|
||||
* Then retrieves a property by name from that object and checks that it's not null and not undefined. It is strongly typed
|
||||
* for the property and will give a compile error if the given name is not a property of the source.
|
||||
*/
|
||||
export function nonNullValueAndProp<TSource, TKey extends keyof TSource>(source: TSource | undefined, name: TKey): NonNullable<TSource[TKey]> {
|
||||
return nonNullProp(nonNullValue(source, <string>name), name);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export async function openUrl(url: string): Promise<void> {
|
||||
await vscode.env.openExternal(vscode.Uri.parse(url));
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { ext } from '../extensionVariables';
|
||||
|
||||
export namespace treeUtils {
|
||||
export interface IThemedIconPath {
|
||||
light: string;
|
||||
dark: string;
|
||||
}
|
||||
|
||||
export function getIconPath(iconName: string): string {
|
||||
return path.join(getResourcesPath(), `${iconName}.svg`);
|
||||
}
|
||||
|
||||
export function getThemedIconPath(iconName: string): IThemedIconPath {
|
||||
return {
|
||||
light: path.join(getResourcesPath(), 'light', `${iconName}.svg`),
|
||||
dark: path.join(getResourcesPath(), 'dark', `${iconName}.svg`)
|
||||
};
|
||||
}
|
||||
|
||||
function getResourcesPath(): string {
|
||||
return ext.context.asAbsolutePath('resources');
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
This folder contains logic related to VS Code project files, like "settings.json", "tasks.json", and "launch.json".
|
|
@ -0,0 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface IExtensionsJson {
|
||||
recommendations?: string[];
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ConfigurationTarget, Uri, workspace, WorkspaceConfiguration } from "vscode";
|
||||
import { ext } from "../extensionVariables";
|
||||
|
||||
/**
|
||||
* Uses ext.prefix 'azureVirtualMachines' unless otherwise specified
|
||||
*/
|
||||
export async function updateGlobalSetting<T = string>(section: string, value: T, prefix: string = ext.prefix): Promise<void> {
|
||||
const projectConfiguration: WorkspaceConfiguration = workspace.getConfiguration(prefix);
|
||||
await projectConfiguration.update(section, value, ConfigurationTarget.Global);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses ext.prefix 'azureVirtualMachines' unless otherwise specified
|
||||
*/
|
||||
export async function updateWorkspaceSetting<T = string>(section: string, value: T, fsPath: string, prefix: string = ext.prefix): Promise<void> {
|
||||
const projectConfiguration: WorkspaceConfiguration = workspace.getConfiguration(prefix, Uri.file(fsPath));
|
||||
await projectConfiguration.update(section, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses ext.prefix 'azureVirtualMachines' unless otherwise specified
|
||||
*/
|
||||
export function getGlobalSetting<T>(key: string, prefix: string = ext.prefix): T | undefined {
|
||||
const projectConfiguration: WorkspaceConfiguration = workspace.getConfiguration(prefix);
|
||||
const result: { globalValue?: T } | undefined = projectConfiguration.inspect<T>(key);
|
||||
return result && result.globalValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses ext.prefix 'azureVirtualMachines' unless otherwise specified
|
||||
*/
|
||||
export function getWorkspaceSetting<T>(key: string, fsPath?: string, prefix: string = ext.prefix): T | undefined {
|
||||
const projectConfiguration: WorkspaceConfiguration = workspace.getConfiguration(prefix, fsPath ? Uri.file(fsPath) : undefined);
|
||||
return projectConfiguration.get<T>(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches through all open folders and gets the current workspace setting (as long as there are no conflicts)
|
||||
* Uses ext.prefix 'azureVirtualMachines' unless otherwise specified
|
||||
*/
|
||||
export function getWorkspaceSettingFromAnyFolder(key: string, prefix: string = ext.prefix): string | undefined {
|
||||
if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) {
|
||||
let result: string | undefined;
|
||||
for (const folder of workspace.workspaceFolders) {
|
||||
const projectConfiguration: WorkspaceConfiguration = workspace.getConfiguration(prefix, folder.uri);
|
||||
const folderResult: string | undefined = projectConfiguration.get<string>(key);
|
||||
if (!result) {
|
||||
result = folderResult;
|
||||
} else if (folderResult && result !== folderResult) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return getGlobalSetting(key, prefix);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IHookCallbackContext } from 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { TestOutputChannel, TestUserInput } from 'vscode-azureextensiondev';
|
||||
import { } from 'vscode-azureextensionui';
|
||||
import { ext } from '../extension.bundle';
|
||||
|
||||
export let longRunningTestsEnabled: boolean;
|
||||
export let testUserInput: TestUserInput = new TestUserInput(vscode);
|
||||
|
||||
// Runs before all tests
|
||||
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
|
||||
this.timeout(120 * 1000);
|
||||
|
||||
await vscode.commands.executeCommand('azureVirtualMachines.refresh'); // activate the extension before tests begin
|
||||
ext.outputChannel = new TestOutputChannel();
|
||||
ext.ui = testUserInput;
|
||||
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
longRunningTestsEnabled = !/^(false|0)?$/i.test(process.env.ENABLE_LONG_RUNNING_TESTS || '');
|
||||
|
||||
// set AzureWebJobsStorage so that it doesn't prompt during tests
|
||||
process.env.AzureWebJobsStorage = 'ignore';
|
||||
});
|
||||
|
||||
suiteTeardown(async function (this: IHookCallbackContext): Promise<void> {
|
||||
this.timeout(90 * 1000);
|
||||
});
|
|
@ -0,0 +1,66 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//
|
||||
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
|
||||
//
|
||||
// This file is providing the test runner to use when running extension tests.
|
||||
// By default the test runner in use is Mocha based.
|
||||
//
|
||||
// You can provide your own test runner if you want to override it by exporting
|
||||
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
|
||||
// host can call to run the tests. The test runner is expected to use console.log
|
||||
// to report the results back to the caller. When the tests are finished, return
|
||||
// a possible error to the callback or null if none.
|
||||
|
||||
import * as path from 'path';
|
||||
// tslint:disable-next-line:no-require-imports no-submodule-imports
|
||||
import testRunner = require('vscode/lib/testrunner');
|
||||
|
||||
const options: { [key: string]: string | boolean | number | object } = {
|
||||
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
|
||||
useColors: true // colored output from test results
|
||||
};
|
||||
|
||||
// You can directly control Mocha options using environment variables beginning with MOCHA_.
|
||||
// For example:
|
||||
// {
|
||||
// "name": "Launch Tests",
|
||||
// "type": "extensionHost",
|
||||
// "request": "launch",
|
||||
// ...
|
||||
// "env": {
|
||||
// "MOCHA_enableTimeouts": "0",
|
||||
// "MOCHA_grep": "tests-to-run"
|
||||
// }
|
||||
//
|
||||
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for all available options
|
||||
|
||||
// Defaults
|
||||
options.reporter = 'mocha-multi-reporters';
|
||||
options.reporterOptions = {
|
||||
reporterEnabled: 'spec, mocha-junit-reporter',
|
||||
mochaJunitReporterReporterOptions: {
|
||||
mochaFile: path.join(__dirname, '..', '..', 'test-results.xml')
|
||||
}
|
||||
};
|
||||
|
||||
for (const envVar of Object.keys(process.env)) {
|
||||
const match: RegExpMatchArray | null = envVar.match(/^mocha_(.+)/i);
|
||||
if (match) {
|
||||
const [, option] = match;
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
let value: string | number = process.env[envVar] || '';
|
||||
if (typeof value === 'string' && !isNaN(parseInt(value))) {
|
||||
value = parseInt(value);
|
||||
}
|
||||
options[option] = value;
|
||||
}
|
||||
}
|
||||
console.warn(`Mocha options: ${JSON.stringify(options, null, 2)}`);
|
||||
|
||||
testRunner.configure(options);
|
||||
|
||||
module.exports = testRunner;
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"extends": "../tslint.json",
|
||||
"rules": {
|
||||
"no-console": false,
|
||||
"no-implicit-dependencies": [
|
||||
true,
|
||||
"dev"
|
||||
],
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
// "arrow-call-signature",
|
||||
"parameter",
|
||||
// "arrow-parameter",
|
||||
"property-declaration",
|
||||
"variable-declaration",
|
||||
"member-variable-declaration"
|
||||
// "object-destructuring",
|
||||
// "array-destructuring"
|
||||
],
|
||||
"no-unexternalized-strings": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": ".",
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedParameters": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"*": [
|
||||
"node_modules/vscode/*",
|
||||
"*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test",
|
||||
"gulpfile.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
{
|
||||
"extends": "tslint-microsoft-contrib",
|
||||
"rules": {
|
||||
"await-promise": [
|
||||
true,
|
||||
"Thenable"
|
||||
],
|
||||
"no-backbone-get-set-outside-model": false,
|
||||
"radix": false,
|
||||
"strict-boolean-expressions": [
|
||||
true,
|
||||
"allow-string",
|
||||
"allow-undefined-union",
|
||||
"allow-mix",
|
||||
"allow-null-union"
|
||||
],
|
||||
"completed-docs": [
|
||||
false,
|
||||
"classes"
|
||||
],
|
||||
"import-name": false,
|
||||
"max-line-length": [
|
||||
false,
|
||||
140
|
||||
],
|
||||
"missing-jsdoc": false,
|
||||
"no-relative-imports": false,
|
||||
"no-void-expression": [
|
||||
true,
|
||||
"ignore-arrow-function-shorthand"
|
||||
],
|
||||
"variable-name": [
|
||||
true,
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-leading-underscore"
|
||||
],
|
||||
"linebreak-style": false,
|
||||
"newline-before-return": false,
|
||||
"no-single-line-block-comment": false,
|
||||
"quotemark": [
|
||||
false,
|
||||
"single"
|
||||
],
|
||||
"no-unexternalized-strings": [
|
||||
true,
|
||||
{
|
||||
"signatures": [
|
||||
"localize",
|
||||
"nls.localize"
|
||||
],
|
||||
"keyIndex": 0,
|
||||
"messageIndex": 1
|
||||
}
|
||||
],
|
||||
"no-implicit-dependencies": [
|
||||
true,
|
||||
[
|
||||
"vscode"
|
||||
]
|
||||
],
|
||||
"switch-final-break": false,
|
||||
"prefer-object-spread": false,
|
||||
"no-return-await": false,
|
||||
"no-parameter-reassignment": false,
|
||||
"no-object-literal-type-assertion": false,
|
||||
"function-name": [
|
||||
true,
|
||||
{
|
||||
"static-method-regex": "^[a-z][\\w_]+$"
|
||||
}
|
||||
],
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
"arrow-call-signature",
|
||||
"parameter",
|
||||
// "arrow-parameter",
|
||||
"property-declaration",
|
||||
"variable-declaration",
|
||||
"member-variable-declaration"
|
||||
],
|
||||
"prefer-template": [
|
||||
true,
|
||||
"allow-single-concat"
|
||||
],
|
||||
"no-use-before-declare": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
//@ts-check
|
||||
|
||||
// See https://github.com/Microsoft/vscode-azuretools/wiki/webpack for guidance
|
||||
|
||||
const process = require('process');
|
||||
const dev = require("vscode-azureextensiondev");
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
|
||||
let DEBUG_WEBPACK = !/^(false|0)?$/i.test(process.env.DEBUG_WEBPACK || '');
|
||||
|
||||
let config = dev.getDefaultWebpackConfig({
|
||||
projectRoot: __dirname,
|
||||
verbosity: DEBUG_WEBPACK ? 'debug' : 'normal',
|
||||
externals:
|
||||
{
|
||||
// Fix "Module not found" errors in ./node_modules/websocket/lib/{BufferUtil,Validation}.js
|
||||
// These files are not in node_modules and so will fail normally at runtime and instead use fallbacks.
|
||||
// Make them as external so webpack doesn't try to process them, and they'll simply fail at runtime as before.
|
||||
'../build/Release/validation': 'commonjs ../build/Release/validation',
|
||||
'../build/default/validation': 'commonjs ../build/default/validation',
|
||||
'../build/Release/bufferutil': 'commonjs ../build/Release/bufferutil',
|
||||
'../build/default/bufferutil': 'commonjs ../build/default/bufferutil',
|
||||
|
||||
// ./getCoreNodeModule.js (path from windowsProcessTree.ts) uses a dynamic require which can't be webpacked
|
||||
'./getCoreNodeModule': 'commonjs getCoreNodeModule',
|
||||
},
|
||||
plugins: [
|
||||
// Copy files to dist folder where the runtime can find them
|
||||
new CopyWebpackPlugin([
|
||||
// getCoreNodeModule.js -> dist/node_modules/getCoreNodeModule.js
|
||||
{ from: './out/src/utils/getCoreNodeModule.js', to: 'node_modules' }
|
||||
])
|
||||
]
|
||||
});
|
||||
|
||||
if (DEBUG_WEBPACK) {
|
||||
console.log('Config:', config);
|
||||
}
|
||||
|
||||
module.exports = config;
|