mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-18 11:01:36 -05:00
Compare commits
75 Commits
1.24.0_rel
...
1.23.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d296b6397e | ||
|
|
05615c796d | ||
|
|
e60b01ac00 | ||
|
|
b68cdbeebe | ||
|
|
7429407029 | ||
|
|
6adeffbc8e | ||
|
|
8a078d2d68 | ||
|
|
eadac3af3a | ||
|
|
8e8d9b5f59 | ||
|
|
93e806cca1 | ||
|
|
98ed0d5274 | ||
|
|
7bca43524e | ||
|
|
a8c983519e | ||
|
|
ac6ef2639f | ||
|
|
35957cc283 | ||
|
|
b054295eac | ||
|
|
5b7a7c9865 | ||
|
|
867faae14f | ||
|
|
4c6b606c82 | ||
|
|
d5daaf918d | ||
|
|
72d48bda61 | ||
|
|
93156ccf04 | ||
|
|
781c7de772 | ||
|
|
41e8b73ac4 | ||
|
|
61254c7298 | ||
|
|
5f59fa021c | ||
|
|
1f65216889 | ||
|
|
c801d46814 | ||
|
|
6c85cf2bdd | ||
|
|
9067204979 | ||
|
|
ac6bc56c4e | ||
|
|
1b5c54dd8c | ||
|
|
4082170522 | ||
|
|
5ecf1c6e6f | ||
|
|
6de11c8107 | ||
|
|
76d7b0a9fe | ||
|
|
ce4c3e9586 | ||
|
|
5190bf376c | ||
|
|
77b9a708df | ||
|
|
a4ee871b88 | ||
|
|
3f4e19fc08 | ||
|
|
571fca6de5 | ||
|
|
5a2fdc4034 | ||
|
|
cc6d84e7f6 | ||
|
|
99e11d2e22 | ||
|
|
9a85123e21 | ||
|
|
56669db6b6 | ||
|
|
8782eeb32f | ||
|
|
7f3d5bac0a | ||
|
|
7a1e0a7d2e | ||
|
|
681ecbd946 | ||
|
|
e7798a8e32 | ||
|
|
b158180ef4 | ||
|
|
7ad9da7fda | ||
|
|
94e2016a16 | ||
|
|
21bb577da8 | ||
|
|
5e8325ba28 | ||
|
|
25b7ccade3 | ||
|
|
57940c581c | ||
|
|
82f9e4e24b | ||
|
|
3e22fcfd2d | ||
|
|
0bc81e1078 | ||
|
|
7b6328dccf | ||
|
|
05124273ea | ||
|
|
b1d4444522 | ||
|
|
4ee2d369cf | ||
|
|
fb28b69bb0 | ||
|
|
f2709c7100 | ||
|
|
3476f5ae38 | ||
|
|
b937fdee7a | ||
|
|
dd9ac2e362 | ||
|
|
403ff6cfec | ||
|
|
4a6226974e | ||
|
|
6a2c47f511 | ||
|
|
3d9a316f4b |
@@ -73,7 +73,6 @@ RUN apt-get update \
|
||||
libnss3 \
|
||||
libxss1 \
|
||||
libasound2 \
|
||||
libgbm1 \
|
||||
xfonts-base \
|
||||
xfonts-terminus \
|
||||
fonts-noto \
|
||||
|
||||
11
.github/CODEOWNERS
vendored
11
.github/CODEOWNERS
vendored
@@ -1,11 +0,0 @@
|
||||
# Lines starting with '#' are comments.
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
# Syntax can be found here: https://docs.github.com/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
|
||||
|
||||
/src/sql/*.d.ts @alanrenmsft @Charles-Gagnon @ranasaria
|
||||
/extensions/resource-deployment/ @ranasaria
|
||||
/extensions/arc/ @ranasaria
|
||||
/extensions/azdata/ @ranasaria
|
||||
/extensions/dacpac/ @kisantia
|
||||
/extensions/schema-compare/ @kisantia
|
||||
/extensions/sql-database-projects/ @Benjin @kisantia
|
||||
7
.github/subscribers.json
vendored
7
.github/subscribers.json
vendored
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"label-to-subscribe-to": [
|
||||
"list of usernames to subscribe",
|
||||
"such as:",
|
||||
"JacksonKearl"
|
||||
]
|
||||
}
|
||||
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
@@ -31,10 +31,7 @@ jobs:
|
||||
with:
|
||||
node-version: 10
|
||||
# TODO: cache node modules
|
||||
# Increase timeout to get around latency issues when fetching certain packages
|
||||
- run: |
|
||||
yarn config set network-timeout 300000
|
||||
yarn --frozen-lockfile
|
||||
- run: yarn --frozen-lockfile
|
||||
name: Install Dependencies
|
||||
- run: yarn electron x64
|
||||
name: Download Electron
|
||||
@@ -82,10 +79,7 @@ jobs:
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '2.x'
|
||||
# Increase timeout to get around latency issues when fetching certain packages
|
||||
- run: |
|
||||
yarn config set network-timeout 300000
|
||||
yarn --frozen-lockfile
|
||||
- run: yarn --frozen-lockfile
|
||||
name: Install Dependencies
|
||||
- run: yarn electron
|
||||
name: Download Electron
|
||||
@@ -118,10 +112,7 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
# Increase timeout to get around latency issues when fetching certain packages
|
||||
- run: |
|
||||
yarn config set network-timeout 300000
|
||||
yarn --frozen-lockfile
|
||||
- run: yarn --frozen-lockfile
|
||||
name: Install Dependencies
|
||||
- run: yarn electron x64
|
||||
name: Download Electron
|
||||
|
||||
50
.github/workflows/deep-classifier-runner.yml
vendored
50
.github/workflows/deep-classifier-runner.yml
vendored
@@ -1,50 +0,0 @@
|
||||
name: "Deep Classifier: Runner"
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 * * * *
|
||||
repository_dispatch:
|
||||
types: [trigger-deep-classifier-runner]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'microsoft/vscode-github-triage-actions'
|
||||
ref: v35
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Install Additional Dependencies
|
||||
# Pulls in a bunch of other packages that arent needed for the rest of the actions
|
||||
run: npm install @azure/storage-blob@12.1.1
|
||||
- name: "Run Classifier: Scraper"
|
||||
uses: ./actions/classifier-deep/apply/fetch-sources
|
||||
with:
|
||||
# slightly overlapping to protect against issues slipping through the cracks if a run is delayed
|
||||
from: 80
|
||||
until: 5
|
||||
configPath: classifier
|
||||
blobContainerName: vscode-issue-classifier
|
||||
blobStorageKey: ${{secrets.AZURE_BLOB_STORAGE_CONNECTION_STRING}}
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade numpy scipy scikit-learn joblib nltk simpletransformers torch torchvision
|
||||
- name: "Run Classifier: Generator"
|
||||
run: python ./actions/classifier-deep/apply/generate-labels/main.py
|
||||
- name: "Run Classifier: Labeler"
|
||||
uses: ./actions/classifier-deep/apply/apply-labels
|
||||
with:
|
||||
configPath: classifier
|
||||
allowLabels: "needs more info|new release"
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
27
.github/workflows/deep-classifier-scraper.yml
vendored
27
.github/workflows/deep-classifier-scraper.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: "Deep Classifier: Scraper"
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [trigger-deep-classifier-scraper]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'microsoft/vscode-github-triage-actions'
|
||||
ref: v35
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Install Additional Dependencies
|
||||
# Pulls in a bunch of other packages that arent needed for the rest of the actions
|
||||
run: npm install @azure/storage-blob@12.1.1
|
||||
- name: "Run Classifier: Scraper"
|
||||
uses: ./actions/classifier-deep/train/fetch-issues
|
||||
with:
|
||||
blobContainerName: vscode-issue-classifier
|
||||
blobStorageKey: ${{secrets.AZURE_BLOB_STORAGE_CONNECTION_STRING}}
|
||||
token: ${{secrets.ISSUE_SCRAPER_TOKEN}}
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
27
.github/workflows/latest-release-monitor.yml
vendored
27
.github/workflows/latest-release-monitor.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Latest Release Monitor
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0/5 * * * *
|
||||
repository_dispatch:
|
||||
types: [trigger-latest-release-monitor]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'microsoft/vscode-github-triage-actions'
|
||||
path: ./actions
|
||||
ref: v35
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Install Storage Module
|
||||
run: npm install @azure/storage-blob@12.1.1
|
||||
- name: Run Latest Release Monitor
|
||||
uses: ./actions/latest-release-monitor
|
||||
with:
|
||||
storageKey: ${{secrets.AZURE_BLOB_STORAGE_CONNECTION_STRING}}
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
2
.vscode/notebooks/api.github-issues
vendored
2
.vscode/notebooks/api.github-issues
vendored
@@ -8,7 +8,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"September 2020\"",
|
||||
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"August 2020\"",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
|
||||
2
.vscode/notebooks/my-work.github-issues
vendored
2
.vscode/notebooks/my-work.github-issues
vendored
@@ -8,7 +8,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks\n\n// current milestone name\n$milestone=milestone:\"September 2020\"",
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks\n\n// current milestone name\n$milestone=milestone:\"August 2020\"",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
|
||||
2
.vscode/notebooks/verification.github-issues
vendored
2
.vscode/notebooks/verification.github-issues
vendored
@@ -14,7 +14,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"September 2020\"",
|
||||
"value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"July 2020\"",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
|
||||
194
.vscode/searches/TrustedTypes.code-search
vendored
194
.vscode/searches/TrustedTypes.code-search
vendored
@@ -1,194 +0,0 @@
|
||||
# Query: .innerHTML =
|
||||
# Flags: CaseSensitive WordMatch
|
||||
# Including: src/vs/**/*.{t,j}s
|
||||
# Excluding: *.test.ts
|
||||
# ContextLines: 3
|
||||
|
||||
22 results - 14 files
|
||||
|
||||
src/vs/base/browser/markdownRenderer.ts:
|
||||
161 const strValue = values[0];
|
||||
162 const span = element.querySelector(`div[data-code="${id}"]`);
|
||||
163 if (span) {
|
||||
164: span.innerHTML = strValue;
|
||||
165 }
|
||||
166 }).catch(err => {
|
||||
167 // ignore
|
||||
|
||||
243 return true;
|
||||
244 }
|
||||
245
|
||||
246: element.innerHTML = insane(renderedMarkdown, {
|
||||
247 allowedSchemes,
|
||||
248 // allowedTags should included everything that markdown renders to.
|
||||
249 // Since we have our own sanitize function for marked, it's possible we missed some tag so let insane make sure.
|
||||
|
||||
src/vs/base/browser/ui/contextview/contextview.ts:
|
||||
157 this.shadowRootHostElement = DOM.$('.shadow-root-host');
|
||||
158 this.container.appendChild(this.shadowRootHostElement);
|
||||
159 this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'open' });
|
||||
160: this.shadowRoot.innerHTML = `
|
||||
161 <style>
|
||||
162 ${SHADOW_ROOT_CSS}
|
||||
163 </style>
|
||||
|
||||
src/vs/code/electron-sandbox/issue/issueReporterMain.ts:
|
||||
57 const platformClass = platform.isWindows ? 'windows' : platform.isLinux ? 'linux' : 'mac';
|
||||
58 addClass(document.body, platformClass); // used by our fonts
|
||||
59
|
||||
60: document.body.innerHTML = BaseHtml();
|
||||
61 const issueReporter = new IssueReporter(configuration);
|
||||
62 issueReporter.render();
|
||||
63 document.body.style.display = 'block';
|
||||
|
||||
src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts:
|
||||
320 content.push(`.highest { color: ${styles.highlightForeground}; }`);
|
||||
321 }
|
||||
322
|
||||
323: styleTag.innerHTML = content.join('\n');
|
||||
324 if (document.head) {
|
||||
325 document.head.appendChild(styleTag);
|
||||
326 }
|
||||
|
||||
src/vs/editor/browser/view/domLineBreaksComputer.ts:
|
||||
107 allCharOffsets[i] = tmp[0];
|
||||
108 allVisibleColumns[i] = tmp[1];
|
||||
109 }
|
||||
110: containerDomNode.innerHTML = sb.build();
|
||||
111
|
||||
112 containerDomNode.style.position = 'absolute';
|
||||
113 containerDomNode.style.top = '10000';
|
||||
|
||||
src/vs/editor/browser/view/viewLayer.ts:
|
||||
507 private _finishRenderingNewLines(ctx: IRendererContext<T>, domNodeIsEmpty: boolean, newLinesHTML: string, wasNew: boolean[]): void {
|
||||
508 const lastChild = <HTMLElement>this.domNode.lastChild;
|
||||
509 if (domNodeIsEmpty || !lastChild) {
|
||||
510: this.domNode.innerHTML = newLinesHTML;
|
||||
511 } else {
|
||||
512 lastChild.insertAdjacentHTML('afterend', newLinesHTML);
|
||||
513 }
|
||||
|
||||
525 private _finishRenderingInvalidLines(ctx: IRendererContext<T>, invalidLinesHTML: string, wasInvalid: boolean[]): void {
|
||||
526 const hugeDomNode = document.createElement('div');
|
||||
527
|
||||
528: hugeDomNode.innerHTML = invalidLinesHTML;
|
||||
529
|
||||
530 for (let i = 0; i < ctx.linesLength; i++) {
|
||||
531 const line = ctx.lines[i];
|
||||
|
||||
src/vs/editor/browser/widget/diffEditorWidget.ts:
|
||||
2157
|
||||
2158 let domNode = document.createElement('div');
|
||||
2159 domNode.className = `view-lines line-delete ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`;
|
||||
2160: domNode.innerHTML = sb.build();
|
||||
2161 Configuration.applyFontInfoSlow(domNode, fontInfo);
|
||||
2162
|
||||
2163 let marginDomNode = document.createElement('div');
|
||||
2164 marginDomNode.className = 'inline-deleted-margin-view-zone';
|
||||
2165: marginDomNode.innerHTML = marginHTML.join('');
|
||||
2166 Configuration.applyFontInfoSlow(marginDomNode, fontInfo);
|
||||
2167
|
||||
2168 return {
|
||||
|
||||
src/vs/editor/standalone/browser/colorizer.ts:
|
||||
40 let text = domNode.firstChild ? domNode.firstChild.nodeValue : '';
|
||||
41 domNode.className += ' ' + theme;
|
||||
42 let render = (str: string) => {
|
||||
43: domNode.innerHTML = str;
|
||||
44 };
|
||||
45 return this.colorize(modeService, text || '', mimeType, options).then(render, (err) => console.error(err));
|
||||
46 }
|
||||
|
||||
src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts:
|
||||
212 if (!this._globalStyleElement) {
|
||||
213 this._globalStyleElement = dom.createStyleSheet();
|
||||
214 this._globalStyleElement.className = 'monaco-colors';
|
||||
215: this._globalStyleElement.innerHTML = this._css;
|
||||
216 this._styleElements.push(this._globalStyleElement);
|
||||
217 }
|
||||
218 return Disposable.None;
|
||||
|
||||
221 private _registerShadowDomContainer(domNode: HTMLElement): IDisposable {
|
||||
222 const styleElement = dom.createStyleSheet(domNode);
|
||||
223 styleElement.className = 'monaco-colors';
|
||||
224: styleElement.innerHTML = this._css;
|
||||
225 this._styleElements.push(styleElement);
|
||||
226 return {
|
||||
227 dispose: () => {
|
||||
|
||||
291 ruleCollector.addRule(generateTokensCSSForColorMap(colorMap));
|
||||
292
|
||||
293 this._css = cssRules.join('\n');
|
||||
294: this._styleElements.forEach(styleElement => styleElement.innerHTML = this._css);
|
||||
295
|
||||
296 TokenizationRegistry.setColorMap(colorMap);
|
||||
297 this._onColorThemeChange.fire(theme);
|
||||
|
||||
src/vs/editor/test/browser/controller/imeTester.ts:
|
||||
55 let content = this._model.getModelLineContent(i);
|
||||
56 r += content + '<br/>';
|
||||
57 }
|
||||
58: output.innerHTML = r;
|
||||
59 }
|
||||
60 }
|
||||
61
|
||||
|
||||
69 let title = document.createElement('div');
|
||||
70 title.className = 'title';
|
||||
71
|
||||
72: title.innerHTML = description + '. Type <strong>' + inputStr + '</strong>';
|
||||
73 container.appendChild(title);
|
||||
74
|
||||
75 let startBtn = document.createElement('button');
|
||||
|
||||
src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts:
|
||||
454
|
||||
455 private getMarkdownDragImage(templateData: MarkdownCellRenderTemplate): HTMLElement {
|
||||
456 const dragImageContainer = DOM.$('.cell-drag-image.monaco-list-row.focused.markdown-cell-row');
|
||||
457: dragImageContainer.innerHTML = templateData.container.outerHTML;
|
||||
458
|
||||
459 // Remove all rendered content nodes after the
|
||||
460 const markdownContent = dragImageContainer.querySelector('.cell.markdown')!;
|
||||
|
||||
611 return null;
|
||||
612 }
|
||||
613
|
||||
614: editorContainer.innerHTML = richEditorText;
|
||||
615
|
||||
616 return dragImageContainer;
|
||||
617 }
|
||||
|
||||
src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts:
|
||||
375 addMouseoverListeners(outputNode, outputId);
|
||||
376 const content = data.content;
|
||||
377 if (content.type === RenderOutputType.Html) {
|
||||
378: outputNode.innerHTML = content.htmlContent;
|
||||
379 cellOutputContainer.appendChild(outputNode);
|
||||
380 domEval(outputNode);
|
||||
381 } else {
|
||||
|
||||
src/vs/workbench/contrib/webview/browser/pre/main.js:
|
||||
386 // apply default styles
|
||||
387 const defaultStyles = newDocument.createElement('style');
|
||||
388 defaultStyles.id = '_defaultStyles';
|
||||
389: defaultStyles.innerHTML = defaultCssRules;
|
||||
390 newDocument.head.prepend(defaultStyles);
|
||||
391
|
||||
392 applyStyles(newDocument, newDocument.body);
|
||||
|
||||
src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts:
|
||||
281
|
||||
282 const content = model.main.textEditorModel.getValue(EndOfLinePreference.LF);
|
||||
283 if (!strings.endsWith(input.resource.path, '.md')) {
|
||||
284: this.content.innerHTML = content;
|
||||
285 this.updateSizeClasses();
|
||||
286 this.decorateContent();
|
||||
287 this.contentDisposables.push(this.keybindingService.onDidUpdateKeybindings(() => this.decorateContent()));
|
||||
|
||||
303 const innerContent = document.createElement('div');
|
||||
304 innerContent.classList.add('walkThroughContent'); // only for markdown files
|
||||
305 const markdown = this.expandMacros(content);
|
||||
306: innerContent.innerHTML = marked(markdown, { renderer });
|
||||
307 this.content.appendChild(innerContent);
|
||||
308
|
||||
309 model.snippets.forEach((snippet, i) => {
|
||||
48
.vscode/searches/es6.code-search
vendored
48
.vscode/searches/es6.code-search
vendored
@@ -2,31 +2,43 @@
|
||||
# Flags: CaseSensitive WordMatch
|
||||
# ContextLines: 2
|
||||
|
||||
12 results - 4 files
|
||||
14 results - 4 files
|
||||
|
||||
src/vs/base/browser/dom.ts:
|
||||
83 };
|
||||
84
|
||||
81 };
|
||||
82
|
||||
83: /** @deprecated ES6 - use classList*/
|
||||
84 export const hasClass: (node: HTMLElement | SVGElement, className: string) => boolean = _classList.hasClass.bind(_classList);
|
||||
85: /** @deprecated ES6 - use classList*/
|
||||
86 export const hasClass: (node: HTMLElement | SVGElement, className: string) => boolean = _classList.hasClass.bind(_classList);
|
||||
86 export const addClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.addClass.bind(_classList);
|
||||
87: /** @deprecated ES6 - use classList*/
|
||||
88 export const addClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.addClass.bind(_classList);
|
||||
88 export const addClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.addClasses.bind(_classList);
|
||||
89: /** @deprecated ES6 - use classList*/
|
||||
90 export const addClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.addClasses.bind(_classList);
|
||||
90 export const removeClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.removeClass.bind(_classList);
|
||||
91: /** @deprecated ES6 - use classList*/
|
||||
92 export const removeClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.removeClass.bind(_classList);
|
||||
92 export const removeClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.removeClasses.bind(_classList);
|
||||
93: /** @deprecated ES6 - use classList*/
|
||||
94 export const removeClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.removeClasses.bind(_classList);
|
||||
95: /** @deprecated ES6 - use classList*/
|
||||
96 export const toggleClass: (node: HTMLElement | SVGElement, className: string, shouldHaveIt?: boolean) => void = _classList.toggleClass.bind(_classList);
|
||||
97
|
||||
94 export const toggleClass: (node: HTMLElement | SVGElement, className: string, shouldHaveIt?: boolean) => void = _classList.toggleClass.bind(_classList);
|
||||
95
|
||||
|
||||
src/vs/base/common/arrays.ts:
|
||||
401
|
||||
402 /**
|
||||
403: * @deprecated ES6: use `Array.find`
|
||||
403: * @deprecated ES6: use `Array.findIndex`
|
||||
404 */
|
||||
405 export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
|
||||
405 export function firstIndex<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): number {
|
||||
|
||||
417
|
||||
418 /**
|
||||
419: * @deprecated ES6: use `Array.find`
|
||||
420 */
|
||||
421 export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
|
||||
|
||||
568
|
||||
569 /**
|
||||
570: * @deprecated ES6: use `Array.find`
|
||||
571 */
|
||||
572 export function find<T>(arr: ArrayLike<T>, predicate: (value: T, index: number, arr: ArrayLike<T>) => any): T | undefined {
|
||||
|
||||
src/vs/base/common/objects.ts:
|
||||
115
|
||||
@@ -54,8 +66,8 @@ src/vs/base/common/strings.ts:
|
||||
170 */
|
||||
171 export function endsWith(haystack: string, needle: string): boolean {
|
||||
|
||||
857
|
||||
858 /**
|
||||
859: * @deprecated ES6
|
||||
860 */
|
||||
861 export function repeat(s: string, count: number): string {
|
||||
861
|
||||
862 /**
|
||||
863: * @deprecated ES6
|
||||
864 */
|
||||
865 export function repeat(s: string, count: number): string {
|
||||
|
||||
58
.vscode/searches/ts36031.code-search
vendored
58
.vscode/searches/ts36031.code-search
vendored
@@ -2,52 +2,18 @@
|
||||
# Flags: RegExp
|
||||
# ContextLines: 2
|
||||
|
||||
8 results - 4 files
|
||||
2 results - 2 files
|
||||
|
||||
src/vs/base/browser/ui/tree/asyncDataTree.ts:
|
||||
241 } : () => 'treeitem',
|
||||
242 isChecked: options.accessibilityProvider!.isChecked ? (e) => {
|
||||
243: return !!(options.accessibilityProvider?.isChecked!(e.element as T));
|
||||
244 } : undefined,
|
||||
245 getAriaLabel(e) {
|
||||
243 } : () => 'treeitem',
|
||||
244 isChecked: options.accessibilityProvider!.isChecked ? (e) => {
|
||||
245: return !!(options.accessibilityProvider?.isChecked!(e.element as T));
|
||||
246 } : undefined,
|
||||
247 getAriaLabel(e) {
|
||||
|
||||
src/vs/platform/list/browser/listService.ts:
|
||||
463
|
||||
464 if (typeof options?.openOnSingleClick !== 'boolean' && options?.configurationService) {
|
||||
465: this.openOnSingleClick = options?.configurationService!.getValue(openModeSettingKey) !== 'doubleClick';
|
||||
466 this._register(options?.configurationService.onDidChangeConfiguration(() => {
|
||||
467: this.openOnSingleClick = options?.configurationService!.getValue(openModeSettingKey) !== 'doubleClick';
|
||||
468 }));
|
||||
469 } else {
|
||||
|
||||
src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts:
|
||||
1526
|
||||
1527 await this._ensureActiveKernel();
|
||||
1528: await this._activeKernel?.cancelNotebookCell!(this._notebookViewModel!.uri, undefined);
|
||||
1529 }
|
||||
1530
|
||||
|
||||
1535
|
||||
1536 await this._ensureActiveKernel();
|
||||
1537: await this._activeKernel?.executeNotebookCell!(this._notebookViewModel!.uri, undefined);
|
||||
1538 }
|
||||
1539
|
||||
|
||||
1553
|
||||
1554 await this._ensureActiveKernel();
|
||||
1555: await this._activeKernel?.cancelNotebookCell!(this._notebookViewModel!.uri, cell.handle);
|
||||
1556 }
|
||||
1557
|
||||
|
||||
1567
|
||||
1568 await this._ensureActiveKernel();
|
||||
1569: await this._activeKernel?.executeNotebookCell!(this._notebookViewModel!.uri, cell.handle);
|
||||
1570 }
|
||||
1571
|
||||
|
||||
src/vs/workbench/contrib/webview/electron-browser/iframeWebviewElement.ts:
|
||||
89 .then(() => this._resourceRequestManager.ensureReady())
|
||||
90 .then(() => {
|
||||
91: this.element?.contentWindow!.postMessage({ channel, args: data }, '*');
|
||||
92 });
|
||||
93 }
|
||||
src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts:
|
||||
254
|
||||
255 return debugDynamicExtensions.map(e => {
|
||||
256: const type = e.contributes?.debuggers![0].type!;
|
||||
257 return {
|
||||
258 label: this.getDebuggerLabel(type)!,
|
||||
|
||||
2
.yarnrc
2
.yarnrc
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "9.3.0"
|
||||
target "9.2.1"
|
||||
runtime "electron"
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,66 +1,5 @@
|
||||
# Change Log
|
||||
|
||||
## Version 1.24.0
|
||||
* Release date: November 12, 2020
|
||||
* Release status: General Availability
|
||||
* SQL Project improvements
|
||||
* Notebook improvements, including in WYSIWYG editor enhancements
|
||||
* Azure Arc improvements
|
||||
* Azure SQL Deployment UX improvements
|
||||
* Azure Browse Connections Preview
|
||||
* Bug Fixes
|
||||
|
||||
## Version 1.23.0
|
||||
* Release date: October 14, 2020
|
||||
* Release status: General Availability
|
||||
* Added deployments of Azure SQL DB and VM
|
||||
* Added PowerShell kernel results streaming support
|
||||
* Added improvements to SQL Database Projects extension
|
||||
* Bug Fixes
|
||||
* Extension Updates:
|
||||
* SQL Server Import
|
||||
* Machine Learning
|
||||
* Schema Compare
|
||||
* Kusto
|
||||
* SQL Assessment
|
||||
* SQL Database Projects
|
||||
* Azure Arc
|
||||
* azdata
|
||||
|
||||
## Version 1.22.1
|
||||
* Release date: September 30, 2020
|
||||
* Release status: General Availability
|
||||
* Fix bug #12615 Active connection filter doesn't untoggle | [#12615](https://github.com/microsoft/azuredatastudio/issues/12615)
|
||||
* Fix bug #12572 Edit Data grid doesn't escape special characters | [#12572](https://github.com/microsoft/azuredatastudio/issues/12572)
|
||||
* Fix bug #12570 Dashboard Explorer table doesn't escape special characters | [#12570](https://github.com/microsoft/azuredatastudio/issues/12570)
|
||||
* Fix bug #12582 Delete row on Edit Data fails | [#12582](https://github.com/microsoft/azuredatastudio/issues/12582)
|
||||
* Fix bug #12646 SQL Notebooks: Cells being treated isolated | [#12646](https://github.com/microsoft/azuredatastudio/issues/12646)
|
||||
|
||||
## Version 1.22.0
|
||||
* Release date: September 22, 2020
|
||||
* Release status: General Availability
|
||||
* New Notebook Features
|
||||
* Supports brand new text cell editing experience based on rich text formatting and seamless conversion to markdown, also known as WYSIWYG toolbar (What You See Is What You Get)
|
||||
* Supports Kusto kernel
|
||||
* Supports pinning of notebooks
|
||||
* Added support for new version of Jupyter Books
|
||||
* Improved Jupyter Shortcuts
|
||||
* Introduced perf loading improvements
|
||||
* Added Azure Arc extension - Users can try out Azure Arc public preview through Azure Data Studio. This includes:
|
||||
* Deploy data controller
|
||||
* Deploy Postgres
|
||||
* Deploy Managed Instance for Azure Arc
|
||||
* Connect to data controller
|
||||
* Access data service dashboards
|
||||
* Azure Arc Jupyter Book
|
||||
* Added new deployment options
|
||||
* Azure SQL Database Edge
|
||||
* (Edge will require Azure SQL Edge Deployment Extension)
|
||||
* Added SQL Database Projects extension - The SQL Database Projects extension brings project-based database development to Azure Data Studio. In this preview release, SQL projects can be created and published from Azure Data Studio.
|
||||
* Added Kusto (KQL) extension - Brings native Kusto experiences in Azure Data Studio for data exploration and data analytics against massive amount of real-time streaming data stored in Azure Data Explorer. This preview release supports connecting and browsing Azure Data Explorer clusters, writing KQL queries as well as authoring notebooks with Kusto kernel.
|
||||
* SQL Server Import extension GA - Announcing the GA of the SQL Server Import extension, features no longer in preview. This extension facilitates importing csv/txt files. Learn more about the extension in [this article](sql-server-import-extension.md).
|
||||
* Resolved [bugs and issues](https://github.com/microsoft/azuredatastudio/issues?q=is%3Aissue+milestone%3A%22September+2020+Release%22+is%3Aclosed).
|
||||
|
||||
## Version 1.21.0
|
||||
* Release date: August 12, 2020
|
||||
* Release status: General Availability
|
||||
|
||||
18
README.md
18
README.md
@@ -19,7 +19,7 @@ Azure Data Studio is a data management tool that enables you to work with SQL Se
|
||||
| [Linux DEB][linux-deb] |
|
||||
|
||||
|
||||
Go to our [download page](https://aka.ms/getazuredatastudio) for more specific instructions.
|
||||
Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions.
|
||||
|
||||
## Try out the latest insiders build from `main`:
|
||||
- [Windows User Installer - **Insiders build**](https://azuredatastudio-update.azurewebsites.net/latest/win32-x64-user/insider)
|
||||
@@ -29,8 +29,6 @@ Go to our [download page](https://aka.ms/getazuredatastudio) for more specific i
|
||||
- [Linux TAR.GZ - **Insiders build**](https://azuredatastudio-update.azurewebsites.net/latest/linux-x64/insider)
|
||||
|
||||
See the [change log](https://github.com/Microsoft/azuredatastudio/blob/main/CHANGELOG.md) for additional details of what's in this release.
|
||||
Go to our [download page](https://aka.ms/getazuredatastudio) for more specific instructions.
|
||||
|
||||
|
||||
## **Feature Highlights**
|
||||
|
||||
@@ -131,10 +129,10 @@ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the [Source EULA](LICENSE.txt).
|
||||
|
||||
[win-user]: https://go.microsoft.com/fwlink/?linkid=2148607
|
||||
[win-system]: https://go.microsoft.com/fwlink/?linkid=2148907
|
||||
[win-zip]: https://go.microsoft.com/fwlink/?linkid=2148908
|
||||
[osx-zip]: https://go.microsoft.com/fwlink/?linkid=2148710
|
||||
[linux-zip]: https://go.microsoft.com/fwlink/?linkid=2148708
|
||||
[linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2148709
|
||||
[linux-deb]: https://go.microsoft.com/fwlink/?linkid=2148806
|
||||
[win-user]: https://go.microsoft.com/fwlink/?linkid=2138608
|
||||
[win-system]: https://go.microsoft.com/fwlink/?linkid=2138704
|
||||
[win-zip]: https://go.microsoft.com/fwlink/?linkid=2138705
|
||||
[osx-zip]: https://go.microsoft.com/fwlink/?linkid=2138609
|
||||
[linux-zip]: https://go.microsoft.com/fwlink/?linkid=2138706
|
||||
[linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2138507
|
||||
[linux-deb]: https://go.microsoft.com/fwlink/?linkid=2138508
|
||||
|
||||
1
build/.gitattributes
vendored
1
build/.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
* text eol=lf
|
||||
@@ -15,7 +15,7 @@
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.6",
|
||||
"@actions/core": "^1.2.3",
|
||||
"@actions/github": "^2.1.1",
|
||||
"axios": "^0.19.2",
|
||||
"ts-node": "^8.6.2",
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@actions/core@^1.2.6":
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.6.tgz#a78d49f41a4def18e88ce47c2cac615d5694bf09"
|
||||
integrity sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==
|
||||
"@actions/core@^1.2.3":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.3.tgz#e844b4fa0820e206075445079130868f95bfca95"
|
||||
integrity sha512-Wp4xnyokakM45Uuj4WLUxdsa8fJjKVl1fDTsPbTEcTcuu0Nb26IPQbOtjmnfaCPGcaoPOOqId8H9NapZ8gii4w==
|
||||
|
||||
"@actions/github@^2.1.1":
|
||||
version "2.1.1"
|
||||
|
||||
@@ -53,7 +53,7 @@ async function uploadBlob(blobService: azure.BlobService, quality: string, blobN
|
||||
}
|
||||
};
|
||||
|
||||
await new Promise<void>((c, e) => blobService.createBlockBlobFromLocalFile(quality, blobName, filePath, blobOptions, err => err ? e(err) : c()));
|
||||
await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(quality, blobName, filePath, blobOptions, err => err ? e(err) : c()));
|
||||
}
|
||||
|
||||
function getEnv(name: string): string {
|
||||
|
||||
@@ -17,7 +17,7 @@ const fileNames = [
|
||||
];
|
||||
|
||||
async function assertContainer(blobService: azure.BlobService, container: string): Promise<void> {
|
||||
await new Promise<void>((c, e) => blobService.createContainerIfNotExists(container, { publicAccessLevel: 'blob' }, err => err ? e(err) : c()));
|
||||
await new Promise((c, e) => blobService.createContainerIfNotExists(container, { publicAccessLevel: 'blob' }, err => err ? e(err) : c()));
|
||||
}
|
||||
|
||||
async function doesBlobExist(blobService: azure.BlobService, container: string, blobName: string): Promise<boolean | undefined> {
|
||||
@@ -33,7 +33,7 @@ async function uploadBlob(blobService: azure.BlobService, container: string, blo
|
||||
}
|
||||
};
|
||||
|
||||
await new Promise<void>((c, e) => blobService.createBlockBlobFromLocalFile(container, blobName, file, blobOptions, err => err ? e(err) : c()));
|
||||
await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(container, blobName, file, blobOptions, err => err ? e(err) : c()));
|
||||
}
|
||||
|
||||
async function publish(commit: string, files: readonly string[]): Promise<void> {
|
||||
|
||||
@@ -87,6 +87,10 @@ steps:
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-darwin-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-reh-darwin-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-reh-web-darwin-min-ci
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
|
||||
@@ -96,6 +96,8 @@ steps:
|
||||
set -e
|
||||
yarn gulp package-rebuild-extensions
|
||||
yarn gulp vscode-darwin-min-ci
|
||||
yarn gulp vscode-reh-darwin-min-ci
|
||||
yarn gulp vscode-reh-web-darwin-min-ci
|
||||
displayName: Build
|
||||
env:
|
||||
VSCODE_MIXIN_PASSWORD: $(github-distro-mixin-password)
|
||||
@@ -128,14 +130,14 @@ steps:
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
|
||||
# - script: |
|
||||
# set -e
|
||||
# node ./node_modules/playwright/install.js
|
||||
# VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/azuredatastudio-reh-web-darwin" \
|
||||
# yarn smoketest --web --headless --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
||||
# displayName: Run smoke tests (Browser)
|
||||
# continueOnError: true
|
||||
# condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
- script: |
|
||||
set -e
|
||||
node ./node_modules/playwright/install.js
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/azuredatastudio-reh-web-darwin" \
|
||||
yarn smoketest --web --headless --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
||||
displayName: Run smoke tests (Browser)
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
@@ -31,10 +31,10 @@ steps:
|
||||
git config user.email "vscode@microsoft.com"
|
||||
git config user.name "VSCode"
|
||||
|
||||
git checkout origin/electron-11.x.y
|
||||
git checkout origin/electron-x.y.z
|
||||
git merge origin/master
|
||||
|
||||
# Push master branch into exploration branch
|
||||
git push origin HEAD:electron-11.x.y
|
||||
git push origin HEAD:electron-x.y.z
|
||||
|
||||
displayName: Sync & Merge Exploration
|
||||
|
||||
@@ -52,25 +52,21 @@ steps:
|
||||
git merge $(node -p "require('./package.json').distro")
|
||||
displayName: Merge distro
|
||||
|
||||
- script: |
|
||||
echo -n $VSCODE_ARCH > .build/arch
|
||||
displayName: Prepare arch cache flag
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
|
||||
vstsFeed: 'npm-vscode'
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
CHILD_CONCURRENCY=1 npm_config_arch=$(NPM_ARCH) yarn --frozen-lockfile
|
||||
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
|
||||
inputs:
|
||||
keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
|
||||
vstsFeed: 'npm-vscode'
|
||||
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||
@@ -89,64 +85,64 @@ steps:
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci
|
||||
yarn gulp vscode-linux-x64-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci
|
||||
yarn gulp vscode-reh-linux-x64-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci
|
||||
yarn gulp vscode-reh-web-linux-x64-min-ci
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
service xvfb start
|
||||
displayName: Start xvfb
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
|
||||
displayName: Run unit tests (Electron)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
DISPLAY=:10 yarn test-browser --build --browser chromium --tfs "Browser Unit Tests"
|
||||
displayName: Run unit tests (Browser)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
# Figure out the full absolute path of the product we just built
|
||||
# including the remote server and configure the integration tests
|
||||
# to run with these builds instead of running out of sources.
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64
|
||||
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \
|
||||
DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests"
|
||||
displayName: Run integration tests (Electron)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
|
||||
DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium
|
||||
displayName: Run integration tests (Browser)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64
|
||||
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \
|
||||
DISPLAY=:10 ./resources/server/test/test-remote-integration.sh
|
||||
displayName: Run remote integration tests (Electron)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'crash-dump-linux-$(VSCODE_ARCH)'
|
||||
artifactName: crash-dump-linux
|
||||
targetPath: .build/crashes
|
||||
displayName: 'Publish Crash Reports'
|
||||
continueOnError: true
|
||||
@@ -161,26 +157,15 @@ steps:
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb"
|
||||
yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm"
|
||||
displayName: Build deb, rpm packages
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap"
|
||||
displayName: Prepare snap package
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'))
|
||||
|
||||
# needed for code signing
|
||||
- task: UseDotNet@2
|
||||
displayName: 'Install .NET Core SDK 2.x'
|
||||
inputs:
|
||||
version: 2.x
|
||||
yarn gulp "vscode-linux-x64-build-deb"
|
||||
yarn gulp "vscode-linux-x64-build-rpm"
|
||||
yarn gulp "vscode-linux-x64-prepare-snap"
|
||||
displayName: Build packages
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '.build/linux/rpm'
|
||||
FolderPath: '.build/linux/rpm/x86_64'
|
||||
Pattern: '*.rpm'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
@@ -201,16 +186,14 @@ steps:
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
VSCODE_ARCH="$(VSCODE_ARCH)" \
|
||||
./build/azure-pipelines/linux/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Pipeline Artifact'
|
||||
inputs:
|
||||
artifactName: 'snap-$(VSCODE_ARCH)'
|
||||
artifactName: snap-x64
|
||||
targetPath: .build/linux/snap-tarball
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'))
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
@@ -4,10 +4,11 @@ REPO="$(pwd)"
|
||||
ROOT="$REPO/.."
|
||||
|
||||
# Publish tarball
|
||||
PLATFORM_LINUX="linux-$VSCODE_ARCH"
|
||||
PLATFORM_LINUX="linux-x64"
|
||||
BUILDNAME="VSCode-$PLATFORM_LINUX"
|
||||
BUILD="$ROOT/$BUILDNAME"
|
||||
BUILD_VERSION="$(date +%s)"
|
||||
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$VSCODE_ARCH-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$VSCODE_ARCH-$BUILD_VERSION.tar.gz"
|
||||
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz"
|
||||
TARBALL_PATH="$ROOT/$TARBALL_FILENAME"
|
||||
|
||||
rm -rf $ROOT/code-*.tar.*
|
||||
@@ -27,36 +28,24 @@ rm -rf $ROOT/vscode-server-*.tar.*
|
||||
node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH"
|
||||
|
||||
# Publish DEB
|
||||
case $VSCODE_ARCH in
|
||||
x64) DEB_ARCH="amd64" ;;
|
||||
*) DEB_ARCH="$VSCODE_ARCH" ;;
|
||||
esac
|
||||
|
||||
PLATFORM_DEB="linux-deb-$VSCODE_ARCH"
|
||||
PLATFORM_DEB="linux-deb-x64"
|
||||
DEB_ARCH="amd64"
|
||||
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
|
||||
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
|
||||
|
||||
node build/azure-pipelines/common/createAsset.js "$PLATFORM_DEB" package "$DEB_FILENAME" "$DEB_PATH"
|
||||
|
||||
# Publish RPM
|
||||
case $VSCODE_ARCH in
|
||||
x64) RPM_ARCH="x86_64" ;;
|
||||
armhf) RPM_ARCH="armv7hl" ;;
|
||||
arm64) RPM_ARCH="aarch64" ;;
|
||||
*) RPM_ARCH="$VSCODE_ARCH" ;;
|
||||
esac
|
||||
|
||||
PLATFORM_RPM="linux-rpm-$VSCODE_ARCH"
|
||||
PLATFORM_RPM="linux-rpm-x64"
|
||||
RPM_ARCH="x86_64"
|
||||
RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)"
|
||||
RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
|
||||
|
||||
node build/azure-pipelines/common/createAsset.js "$PLATFORM_RPM" package "$RPM_FILENAME" "$RPM_PATH"
|
||||
|
||||
if [ "$VSCODE_ARCH" == "x64" ]; then
|
||||
# Publish Snap
|
||||
# Pack snap tarball artifact, in order to preserve file perms
|
||||
mkdir -p $REPO/.build/linux/snap-tarball
|
||||
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$VSCODE_ARCH.tar.gz"
|
||||
rm -rf $SNAP_TARBALL_PATH
|
||||
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)
|
||||
fi
|
||||
# Publish Snap
|
||||
# Pack snap tarball artifact, in order to preserve file perms
|
||||
mkdir -p $REPO/.build/linux/snap-tarball
|
||||
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz"
|
||||
rm -rf $SNAP_TARBALL_PATH
|
||||
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)
|
||||
|
||||
@@ -91,7 +91,8 @@ steps:
|
||||
- script: |
|
||||
set -e
|
||||
yarn gulp vscode-linux-x64-min-ci
|
||||
yarn gulp vscode-web-min-ci
|
||||
yarn gulp vscode-reh-linux-x64-min-ci
|
||||
yarn gulp vscode-reh-web-linux-x64-min-ci
|
||||
displayName: Build
|
||||
env:
|
||||
VSCODE_MIXIN_PASSWORD: $(github-distro-mixin-password)
|
||||
@@ -133,8 +134,7 @@ steps:
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/azuredatastudio-linux-x64
|
||||
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||
export INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
export NO_CLEANUP=1
|
||||
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
DISPLAY=:10 node ./scripts/test-extensions-unit.js ${{ extension }}
|
||||
displayName: 'Run ${{ extension }} Stable Extension Unit Tests'
|
||||
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
@@ -149,15 +149,6 @@ steps:
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(variables['RUN_UNSTABLE_TESTS'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
mkdir -p $(Build.ArtifactStagingDirectory)/logs/linux-x64
|
||||
cd /tmp
|
||||
tar -czvf $(Build.ArtifactStagingDirectory)/logs/linux-x64/logs-linux-x64.tar.gz adsuser*
|
||||
displayName: Archive Logs
|
||||
continueOnError: true
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
yarn gulp vscode-linux-x64-build-deb
|
||||
@@ -230,7 +221,6 @@ steps:
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: drop'
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
@@ -13,12 +13,6 @@ resources:
|
||||
- container: vscode-x64
|
||||
image: vscodehub.azurecr.io/vscode-linux-build-agent:x64
|
||||
endpoint: VSCodeHub
|
||||
- container: vscode-arm64
|
||||
image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-arm64
|
||||
endpoint: VSCodeHub
|
||||
- container: vscode-armhf
|
||||
image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-armhf
|
||||
endpoint: VSCodeHub
|
||||
- container: snapcraft
|
||||
image: snapcore/snapcraft:stable
|
||||
|
||||
@@ -70,9 +64,6 @@ stages:
|
||||
- job: Linux
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
|
||||
container: vscode-x64
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
NPM_ARCH: x64
|
||||
steps:
|
||||
- template: linux/product-build-linux.yml
|
||||
|
||||
@@ -81,28 +72,22 @@ stages:
|
||||
- Linux
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
|
||||
container: snapcraft
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
steps:
|
||||
- template: linux/snap-build-linux.yml
|
||||
|
||||
- job: LinuxArmhf
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'))
|
||||
container: vscode-armhf
|
||||
variables:
|
||||
VSCODE_ARCH: armhf
|
||||
NPM_ARCH: armv7l
|
||||
steps:
|
||||
- template: linux/product-build-linux.yml
|
||||
- template: linux/product-build-linux-multiarch.yml
|
||||
|
||||
- job: LinuxArm64
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARM64'], 'true'))
|
||||
container: vscode-arm64
|
||||
variables:
|
||||
VSCODE_ARCH: arm64
|
||||
NPM_ARCH: arm64
|
||||
steps:
|
||||
- template: linux/product-build-linux.yml
|
||||
- template: linux/product-build-linux-multiarch.yml
|
||||
|
||||
- job: LinuxAlpine
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'))
|
||||
|
||||
@@ -52,13 +52,9 @@ steps:
|
||||
displayName: Merge distro
|
||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
|
||||
|
||||
- script: |
|
||||
echo -n $VSCODE_ARCH > .build/arch
|
||||
displayName: Prepare arch cache flag
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
|
||||
vstsFeed: 'npm-vscode'
|
||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
|
||||
@@ -71,7 +67,7 @@ steps:
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
|
||||
inputs:
|
||||
keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
|
||||
vstsFeed: 'npm-vscode'
|
||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
|
||||
@@ -116,8 +112,8 @@ steps:
|
||||
yarn gulp compile-build
|
||||
yarn gulp compile-extensions-build
|
||||
yarn gulp minify-vscode
|
||||
yarn gulp vscode-reh-linux-x64-min
|
||||
yarn gulp vscode-reh-web-linux-x64-min
|
||||
yarn gulp minify-vscode-reh
|
||||
yarn gulp minify-vscode-reh-web
|
||||
displayName: Compile
|
||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
- template: sql-product-compile.yml
|
||||
|
||||
- job: macOS
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), ne(variables['VSCODE_QUALITY'], 'saw'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'))
|
||||
pool:
|
||||
vmImage: macOS-latest
|
||||
dependsOn:
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
timeoutInMinutes: 180
|
||||
|
||||
- job: macOS_Signing
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), eq(variables['signed'], true), ne(variables['VSCODE_QUALITY'], 'saw'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true'), eq(variables['signed'], true))
|
||||
pool:
|
||||
vmImage: macOS-latest
|
||||
dependsOn:
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
timeoutInMinutes: 70
|
||||
|
||||
- job: LinuxWeb
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_WEB'], 'true'), ne(variables['VSCODE_QUALITY'], 'saw'))
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_WEB'], 'true'))
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
container: linux-x64
|
||||
@@ -61,15 +61,15 @@ jobs:
|
||||
steps:
|
||||
- template: web/sql-product-build-web.yml
|
||||
|
||||
# - job: Docker
|
||||
# condition: and(succeeded(), eq(variables['VSCODE_BUILD_DOCKER'], 'true'))
|
||||
# pool:
|
||||
# vmImage: 'Ubuntu-16.04'
|
||||
# container: linux-x64
|
||||
# dependsOn:
|
||||
# - Linux
|
||||
# steps:
|
||||
# - template: docker/sql-product-build-docker.yml
|
||||
- job: Docker
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_DOCKER'], 'true'))
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
container: linux-x64
|
||||
dependsOn:
|
||||
- Linux
|
||||
steps:
|
||||
- template: docker/sql-product-build-docker.yml
|
||||
|
||||
- job: Windows
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32'], 'true'))
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
dependsOn:
|
||||
- macOS
|
||||
- Linux
|
||||
# - Docker
|
||||
- Docker
|
||||
- Windows
|
||||
- Windows_Test
|
||||
- LinuxWeb
|
||||
|
||||
@@ -96,8 +96,8 @@ steps:
|
||||
yarn gulp compile-build
|
||||
yarn gulp compile-extensions-build
|
||||
yarn gulp minify-vscode
|
||||
yarn gulp vscode-reh-linux-x64-min
|
||||
yarn gulp vscode-reh-web-linux-x64-min
|
||||
yarn gulp minify-vscode-reh
|
||||
yarn gulp minify-vscode-reh-web
|
||||
displayName: Compile
|
||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ $ServerZipLocation = "$Repo\.build\win32-$Arch\server"
|
||||
$ServerZip = "$ServerZipLocation\azuredatastudio-server-win32-$Arch.zip"
|
||||
|
||||
# Create server archive
|
||||
# New-Item $ServerZipLocation -ItemType Directory # this will throw even when success for we don't want to exec this
|
||||
New-Item $ServerZipLocation -ItemType Directory # this will throw even when success for we don't want to exec this
|
||||
$global:LASTEXITCODE = 0
|
||||
# exec { Rename-Item -Path $LegacyServer -NewName $ServerName } "Rename Item"
|
||||
# exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r } "Zip Server"
|
||||
exec { Rename-Item -Path $LegacyServer -NewName $ServerName } "Rename Item"
|
||||
exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r } "Zip Server"
|
||||
|
||||
exec { node build/azure-pipelines/common/copyArtifacts.js } "Copy Artifacts"
|
||||
|
||||
@@ -95,8 +95,8 @@ steps:
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { yarn gulp "package-rebuild-extensions" }
|
||||
exec { yarn gulp "vscode-win32-x64-min-ci" }
|
||||
exec { yarn gulp "vscode-reh-win32-x64-min" }
|
||||
exec { yarn gulp "vscode-reh-web-win32-x64-min" }
|
||||
exec { yarn gulp "vscode-reh-win32-x64-min-ci" }
|
||||
exec { yarn gulp "vscode-reh-web-win32-x64-min-ci" }
|
||||
exec { yarn gulp "vscode-win32-x64-code-helper" }
|
||||
exec { yarn gulp "vscode-win32-x64-inno-updater" }
|
||||
displayName: Build
|
||||
@@ -131,7 +131,7 @@ steps:
|
||||
$AppRoot = "$(agent.builddirectory)\azuredatastudio-win32-x64"
|
||||
$AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json
|
||||
$AppNameShort = $AppProductJson.nameShort
|
||||
# exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\azuredatastudio-reh-win32-x64"; .\scripts\test-integration.bat --build --tfs "Integration Tests" }
|
||||
exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\azuredatastudio-reh-win32-x64"; .\scripts\test-integration.bat --build --tfs "Integration Tests" }
|
||||
displayName: Run integration tests (Electron)
|
||||
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
|
||||
|
||||
@@ -104,7 +104,6 @@ const indentationFilter = [
|
||||
'!extensions/admin-tool-ext-win/ssmsmin/**',
|
||||
'!extensions/resource-deployment/notebooks/**',
|
||||
'!extensions/mssql/notebooks/**',
|
||||
'!extensions/azurehybridtoolkit/notebooks/**',
|
||||
'!extensions/integration-tests/testData/**',
|
||||
'!extensions/arc/src/controller/generated/**',
|
||||
'!extensions/sql-database-projects/resources/templates/*.xml',
|
||||
@@ -179,9 +178,7 @@ const copyrightFilter = [
|
||||
'!extensions/mssql/src/prompts/**',
|
||||
'!extensions/kusto/src/prompts/**',
|
||||
'!extensions/notebook/resources/jupyter_config/**',
|
||||
'!extensions/azurehybridtoolkit/notebooks/**',
|
||||
'!extensions/query-history/images/**',
|
||||
'!extensions/sql/build/update-grammar.js',
|
||||
'!**/*.gif',
|
||||
'!**/*.xlf',
|
||||
'!**/*.dacpac',
|
||||
|
||||
@@ -261,7 +261,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
||||
.pipe(fileLengthFilter.restore)
|
||||
.pipe(util.skipDirectories())
|
||||
.pipe(util.fixWin32DirectoryPermissions())
|
||||
.pipe(electron(_.extend({}, config, { platform, arch: arch === 'armhf' ? 'arm' : arch, ffmpegChromium: true })))
|
||||
.pipe(electron(_.extend({}, config, { platform, arch, ffmpegChromium: true })))
|
||||
.pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'], { dot: true }));
|
||||
|
||||
if (platform === 'linux') {
|
||||
@@ -345,7 +345,7 @@ const BUILD_TARGETS = [
|
||||
{ platform: 'darwin', arch: null, opts: { stats: true } },
|
||||
{ platform: 'linux', arch: 'ia32' },
|
||||
{ platform: 'linux', arch: 'x64' },
|
||||
{ platform: 'linux', arch: 'armhf' },
|
||||
{ platform: 'linux', arch: 'arm' },
|
||||
{ platform: 'linux', arch: 'arm64' },
|
||||
];
|
||||
BUILD_TARGETS.forEach(buildTarget => {
|
||||
|
||||
@@ -23,7 +23,7 @@ const commit = util.getVersion(root);
|
||||
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
function getDebPackageArch(arch) {
|
||||
return { x64: 'amd64', armhf: 'armhf', arm64: 'arm64' }[arch];
|
||||
return { x64: 'amd64', arm: 'armhf', arm64: 'arm64' }[arch];
|
||||
}
|
||||
|
||||
function prepareDebPackage(arch) {
|
||||
@@ -53,11 +53,6 @@ function prepareDebPackage(arch) {
|
||||
.pipe(replace('@@LICENSE@@', product.licenseName))
|
||||
.pipe(rename('usr/share/appdata/' + product.applicationName + '.appdata.xml'));
|
||||
|
||||
const workspaceMime = gulp.src('resources/linux/code-workspace.xml', { base: '.' })
|
||||
.pipe(replace('@@NAME_LONG@@', product.nameLong))
|
||||
.pipe(replace('@@NAME@@', product.applicationName))
|
||||
.pipe(rename('usr/share/mime/packages/' + product.applicationName + '-workspace.xml'));
|
||||
|
||||
const icon = gulp.src('resources/linux/code.png', { base: '.' })
|
||||
.pipe(rename('usr/share/pixmaps/' + product.linuxIconName + '.png'));
|
||||
|
||||
@@ -101,7 +96,7 @@ function prepareDebPackage(arch) {
|
||||
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
|
||||
.pipe(rename('DEBIAN/postinst'));
|
||||
|
||||
const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, code);
|
||||
const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, icon, bash_completion, zsh_completion, code);
|
||||
|
||||
return all.pipe(vfs.dest(destination));
|
||||
};
|
||||
@@ -121,7 +116,7 @@ function getRpmBuildPath(rpmArch) {
|
||||
}
|
||||
|
||||
function getRpmPackageArch(arch) {
|
||||
return { x64: 'x86_64', armhf: 'armv7hl', arm64: 'aarch64' }[arch];
|
||||
return { x64: 'x86_64', arm: 'armhf', arm64: 'arm64' }[arch];
|
||||
}
|
||||
|
||||
function prepareRpmPackage(arch) {
|
||||
@@ -150,11 +145,6 @@ function prepareRpmPackage(arch) {
|
||||
.pipe(replace('@@LICENSE@@', product.licenseName))
|
||||
.pipe(rename('usr/share/appdata/' + product.applicationName + '.appdata.xml'));
|
||||
|
||||
const workspaceMime = gulp.src('resources/linux/code-workspace.xml', { base: '.' })
|
||||
.pipe(replace('@@NAME_LONG@@', product.nameLong))
|
||||
.pipe(replace('@@NAME@@', product.applicationName))
|
||||
.pipe(rename('BUILD/usr/share/mime/packages/' + product.applicationName + '-workspace.xml'));
|
||||
|
||||
const icon = gulp.src('resources/linux/code.png', { base: '.' })
|
||||
.pipe(rename('BUILD/usr/share/pixmaps/' + product.linuxIconName + '.png'));
|
||||
|
||||
@@ -185,7 +175,7 @@ function prepareRpmPackage(arch) {
|
||||
const specIcon = gulp.src('resources/linux/rpm/code.xpm', { base: '.' })
|
||||
.pipe(rename('SOURCES/' + product.applicationName + '.xpm'));
|
||||
|
||||
const all = es.merge(code, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, spec, specIcon);
|
||||
const all = es.merge(code, desktops, appdata, icon, bash_completion, zsh_completion, spec, specIcon);
|
||||
|
||||
return all.pipe(vfs.dest(getRpmBuildPath(rpmArch)));
|
||||
};
|
||||
@@ -259,23 +249,33 @@ function buildSnapPackage(arch) {
|
||||
|
||||
const BUILD_TARGETS = [
|
||||
{ arch: 'x64' },
|
||||
{ arch: 'armhf' },
|
||||
{ arch: 'arm' },
|
||||
{ arch: 'arm64' },
|
||||
];
|
||||
|
||||
BUILD_TARGETS.forEach(({ arch }) => {
|
||||
const debArch = getDebPackageArch(arch);
|
||||
const prepareDebTask = task.define(`vscode-linux-${arch}-prepare-deb`, task.series(util.rimraf(`.build/linux/deb/${debArch}`), prepareDebPackage(arch)));
|
||||
const buildDebTask = task.define(`vscode-linux-${arch}-build-deb`, task.series(prepareDebTask, buildDebPackage(arch)));
|
||||
gulp.task(buildDebTask);
|
||||
BUILD_TARGETS.forEach((buildTarget) => {
|
||||
const arch = buildTarget.arch;
|
||||
|
||||
const rpmArch = getRpmPackageArch(arch);
|
||||
const prepareRpmTask = task.define(`vscode-linux-${arch}-prepare-rpm`, task.series(util.rimraf(`.build/linux/rpm/${rpmArch}`), prepareRpmPackage(arch)));
|
||||
const buildRpmTask = task.define(`vscode-linux-${arch}-build-rpm`, task.series(prepareRpmTask, buildRpmPackage(arch)));
|
||||
gulp.task(buildRpmTask);
|
||||
{
|
||||
const debArch = getDebPackageArch(arch);
|
||||
const prepareDebTask = task.define(`vscode-linux-${arch}-prepare-deb`, task.series(util.rimraf(`.build/linux/deb/${debArch}`), prepareDebPackage(arch)));
|
||||
// gulp.task(prepareDebTask);
|
||||
const buildDebTask = task.define(`vscode-linux-${arch}-build-deb`, task.series(prepareDebTask, buildDebPackage(arch)));
|
||||
gulp.task(buildDebTask);
|
||||
}
|
||||
|
||||
const prepareSnapTask = task.define(`vscode-linux-${arch}-prepare-snap`, task.series(util.rimraf(`.build/linux/snap/${arch}`), prepareSnapPackage(arch)));
|
||||
gulp.task(prepareSnapTask);
|
||||
const buildSnapTask = task.define(`vscode-linux-${arch}-build-snap`, task.series(prepareSnapTask, buildSnapPackage(arch)));
|
||||
gulp.task(buildSnapTask);
|
||||
{
|
||||
const rpmArch = getRpmPackageArch(arch);
|
||||
const prepareRpmTask = task.define(`vscode-linux-${arch}-prepare-rpm`, task.series(util.rimraf(`.build/linux/rpm/${rpmArch}`), prepareRpmPackage(arch)));
|
||||
// gulp.task(prepareRpmTask);
|
||||
const buildRpmTask = task.define(`vscode-linux-${arch}-build-rpm`, task.series(prepareRpmTask, buildRpmPackage(arch)));
|
||||
gulp.task(buildRpmTask);
|
||||
}
|
||||
|
||||
{
|
||||
const prepareSnapTask = task.define(`vscode-linux-${arch}-prepare-snap`, task.series(util.rimraf(`.build/linux/snap/${arch}`), prepareSnapPackage(arch)));
|
||||
gulp.task(prepareSnapTask);
|
||||
const buildSnapTask = task.define(`vscode-linux-${arch}-build-snap`, task.series(prepareSnapTask, buildSnapPackage(arch)));
|
||||
gulp.task(buildSnapTask);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ function getElectron(arch) {
|
||||
return () => {
|
||||
const electronOpts = _.extend({}, exports.config, {
|
||||
platform: process.platform,
|
||||
arch: arch === 'armhf' ? 'arm' : arch,
|
||||
arch,
|
||||
ffmpegChromium: true,
|
||||
keepDefaultApp: true
|
||||
});
|
||||
|
||||
@@ -61,7 +61,7 @@ function getElectron(arch: string): () => NodeJS.ReadWriteStream {
|
||||
return () => {
|
||||
const electronOpts = _.extend({}, config, {
|
||||
platform: process.platform,
|
||||
arch: arch === 'armhf' ? 'arm' : arch,
|
||||
arch,
|
||||
ffmpegChromium: true,
|
||||
keepDefaultApp: true
|
||||
});
|
||||
|
||||
@@ -207,25 +207,25 @@ const externalExtensions = [
|
||||
// they get packaged separately. Adding extension name here, will make the build to create
|
||||
// a separate vsix package for the extension and the extension will be excluded from the main package.
|
||||
// Any extension not included here will be installed by default.
|
||||
'admin-pack',
|
||||
'admin-tool-ext-win',
|
||||
'agent',
|
||||
'arc',
|
||||
'asde-deployment',
|
||||
'azdata',
|
||||
'cms',
|
||||
'dacpac',
|
||||
'data-workspace',
|
||||
'import',
|
||||
'profiler',
|
||||
'admin-pack',
|
||||
'dacpac',
|
||||
'schema-compare',
|
||||
'cms',
|
||||
'query-history',
|
||||
'kusto',
|
||||
'liveshare',
|
||||
'machine-learning',
|
||||
'profiler',
|
||||
'query-history',
|
||||
'schema-compare',
|
||||
'sql-assessment',
|
||||
'sql-database-projects',
|
||||
'machine-learning',
|
||||
'sql-assessment',
|
||||
'asde-deployment',
|
||||
'sql-migration',
|
||||
'data-workspace'
|
||||
];
|
||||
// extensions that require a rebuild since they have native parts
|
||||
const rebuildExtensions = [
|
||||
|
||||
@@ -241,25 +241,25 @@ const externalExtensions = [
|
||||
// they get packaged separately. Adding extension name here, will make the build to create
|
||||
// a separate vsix package for the extension and the extension will be excluded from the main package.
|
||||
// Any extension not included here will be installed by default.
|
||||
'admin-pack',
|
||||
'admin-tool-ext-win',
|
||||
'agent',
|
||||
'arc',
|
||||
'asde-deployment',
|
||||
'azdata',
|
||||
'cms',
|
||||
'dacpac',
|
||||
'data-workspace',
|
||||
'import',
|
||||
'profiler',
|
||||
'admin-pack',
|
||||
'dacpac',
|
||||
'schema-compare',
|
||||
'cms',
|
||||
'query-history',
|
||||
'kusto',
|
||||
'liveshare',
|
||||
'machine-learning',
|
||||
'profiler',
|
||||
'query-history',
|
||||
'schema-compare',
|
||||
'sql-assessment',
|
||||
'sql-database-projects',
|
||||
'machine-learning',
|
||||
'sql-assessment',
|
||||
'asde-deployment',
|
||||
'sql-migration',
|
||||
'data-workspace'
|
||||
];
|
||||
|
||||
// extensions that require a rebuild since they have native parts
|
||||
|
||||
@@ -206,10 +206,6 @@
|
||||
"name": "vs/workbench/contrib/webview",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/webviewPanel",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/customEditor",
|
||||
"project": "vscode-workbench"
|
||||
|
||||
@@ -1004,7 +1004,7 @@ function createResource(project: string, slug: string, xlfFile: File, apiHostnam
|
||||
* https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files
|
||||
*/
|
||||
function updateResource(project: string, slug: string, xlfFile: File, apiHostname: string, credentials: string): Promise<any> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = JSON.stringify({ content: xlfFile.contents.toString() });
|
||||
const options = {
|
||||
hostname: apiHostname,
|
||||
|
||||
@@ -53,13 +53,6 @@ const CORE_TYPES = [
|
||||
'trimLeft',
|
||||
'trimRight'
|
||||
];
|
||||
// Types that are defined in a common layer but are known to be only
|
||||
// available in native environments should not be allowed in browser
|
||||
const NATIVE_TYPES = [
|
||||
'NativeParsedArgs',
|
||||
'INativeEnvironmentService',
|
||||
'INativeWindowConfiguration'
|
||||
];
|
||||
const RULES = [
|
||||
// Tests: skip
|
||||
{
|
||||
@@ -75,37 +68,6 @@ const RULES = [
|
||||
'MessageEvent',
|
||||
'data'
|
||||
],
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts',
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
// Common: vs/platform/environment/common/argv.ts
|
||||
{
|
||||
target: '**/{vs,sql}/platform/environment/common/argv.ts',
|
||||
disallowedTypes: [ /* Ignore native types that are defined from here */],
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts',
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
// Common: vs/platform/environment/common/environment.ts
|
||||
{
|
||||
target: '**/{vs,sql}/platform/environment/common/environment.ts',
|
||||
disallowedTypes: [ /* Ignore native types that are defined from here */],
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts',
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
// Common: vs/platform/windows/common/windows.ts
|
||||
{
|
||||
target: '**/{vs,sql}/platform/windows/common/windows.ts',
|
||||
disallowedTypes: [ /* Ignore native types that are defined from here */],
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts',
|
||||
'@types/node' // no node.js
|
||||
@@ -119,7 +81,6 @@ const RULES = [
|
||||
// Safe access to global
|
||||
'global'
|
||||
],
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts',
|
||||
'@types/node' // no node.js
|
||||
@@ -129,7 +90,6 @@ const RULES = [
|
||||
{
|
||||
target: '**/{vs,sql}/**/common/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts',
|
||||
'@types/node' // no node.js
|
||||
@@ -139,7 +99,6 @@ const RULES = [
|
||||
{
|
||||
target: '**/{vs,sql}/**/browser/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
@@ -148,7 +107,6 @@ const RULES = [
|
||||
{
|
||||
target: '**/src/{vs,sql}/editor/contrib/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
@@ -174,7 +132,7 @@ const RULES = [
|
||||
},
|
||||
// Electron (sandbox)
|
||||
{
|
||||
target: '**/{vs,sql}/**/electron-sandbox/**',
|
||||
target: '**/vs/**/electron-sandbox/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
@@ -204,7 +162,7 @@ let hasErrors = false;
|
||||
function checkFile(program, sourceFile, rule) {
|
||||
checkNode(sourceFile);
|
||||
function checkNode(node) {
|
||||
var _a, _b;
|
||||
var _a;
|
||||
if (node.kind !== ts.SyntaxKind.Identifier) {
|
||||
return ts.forEachChild(node, checkNode); // recurse down
|
||||
}
|
||||
@@ -212,12 +170,6 @@ function checkFile(program, sourceFile, rule) {
|
||||
if ((_a = rule.allowedTypes) === null || _a === void 0 ? void 0 : _a.some(allowed => allowed === text)) {
|
||||
return; // override
|
||||
}
|
||||
if ((_b = rule.disallowedTypes) === null || _b === void 0 ? void 0 : _b.some(disallowed => disallowed === text)) {
|
||||
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
||||
console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
|
||||
hasErrors = true;
|
||||
return;
|
||||
}
|
||||
const checker = program.getTypeChecker();
|
||||
const symbol = checker.getSymbolAtLocation(node);
|
||||
if (symbol) {
|
||||
|
||||
@@ -55,14 +55,6 @@ const CORE_TYPES = [
|
||||
'trimRight'
|
||||
];
|
||||
|
||||
// Types that are defined in a common layer but are known to be only
|
||||
// available in native environments should not be allowed in browser
|
||||
const NATIVE_TYPES = [
|
||||
'NativeParsedArgs',
|
||||
'INativeEnvironmentService',
|
||||
'INativeWindowConfiguration'
|
||||
];
|
||||
|
||||
const RULES = [
|
||||
|
||||
// Tests: skip
|
||||
@@ -81,40 +73,6 @@ const RULES = [
|
||||
'MessageEvent',
|
||||
'data'
|
||||
],
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts', // no DOM
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
|
||||
// Common: vs/platform/environment/common/argv.ts
|
||||
{
|
||||
target: '**/{vs,sql}/platform/environment/common/argv.ts',
|
||||
disallowedTypes: [/* Ignore native types that are defined from here */],
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts', // no DOM
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
|
||||
// Common: vs/platform/environment/common/environment.ts
|
||||
{
|
||||
target: '**/{vs,sql}/platform/environment/common/environment.ts',
|
||||
disallowedTypes: [/* Ignore native types that are defined from here */],
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts', // no DOM
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
|
||||
// Common: vs/platform/windows/common/windows.ts
|
||||
{
|
||||
target: '**/{vs,sql}/platform/windows/common/windows.ts',
|
||||
disallowedTypes: [/* Ignore native types that are defined from here */],
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts', // no DOM
|
||||
'@types/node' // no node.js
|
||||
@@ -130,7 +88,6 @@ const RULES = [
|
||||
// Safe access to global
|
||||
'global'
|
||||
],
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts', // no DOM
|
||||
'@types/node' // no node.js
|
||||
@@ -141,7 +98,6 @@ const RULES = [
|
||||
{
|
||||
target: '**/{vs,sql}/**/common/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'lib.dom.d.ts', // no DOM
|
||||
'@types/node' // no node.js
|
||||
@@ -152,7 +108,6 @@ const RULES = [
|
||||
{
|
||||
target: '**/{vs,sql}/**/browser/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
@@ -162,7 +117,6 @@ const RULES = [
|
||||
{
|
||||
target: '**/src/{vs,sql}/editor/contrib/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedTypes: NATIVE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
@@ -191,7 +145,7 @@ const RULES = [
|
||||
|
||||
// Electron (sandbox)
|
||||
{
|
||||
target: '**/{vs,sql}/**/electron-sandbox/**',
|
||||
target: '**/vs/**/electron-sandbox/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
@@ -227,7 +181,6 @@ interface IRule {
|
||||
skip?: boolean;
|
||||
allowedTypes?: string[];
|
||||
disallowedDefinitions?: string[];
|
||||
disallowedTypes?: string[];
|
||||
}
|
||||
|
||||
let hasErrors = false;
|
||||
@@ -246,14 +199,6 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule)
|
||||
return; // override
|
||||
}
|
||||
|
||||
if (rule.disallowedTypes?.some(disallowed => disallowed === text)) {
|
||||
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
||||
console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
|
||||
|
||||
hasErrors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const symbol = checker.getSymbolAtLocation(node);
|
||||
if (symbol) {
|
||||
|
||||
@@ -15,7 +15,7 @@ const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn';
|
||||
const rootDir = path.resolve(__dirname, '..', '..');
|
||||
|
||||
function runProcess(command: string, args: ReadonlyArray<string> = []) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env });
|
||||
child.on('exit', err => !err ? resolve() : process.exit(err ?? 1));
|
||||
child.on('error', reject);
|
||||
|
||||
@@ -60,12 +60,12 @@
|
||||
"git": {
|
||||
"name": "electron",
|
||||
"repositoryUrl": "https://github.com/electron/electron",
|
||||
"commitHash": "fb03807cd21915ddc3aa2521ba4f5ba14597bd7e"
|
||||
"commitHash": "03c7a54dc534ce1867d4393b9b1a6989d4a7e005"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "9.3.0"
|
||||
"version": "9.2.1"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
||||
"version": "0.49.0",
|
||||
"version": "0.48.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.7 7.9L15.8 15L15 15.8L7.9 8.7L0.8 15.8L0 15L7.1 7.9L0 0.8L0.8 0L7.9 7.1L15 0L15.8 0.8L8.7 7.9Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 228 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" width="16" height="16">
|
||||
<path d="M960 1920q-133 0-255-34t-230-96-194-150-150-195-97-229T0 960q0-133 34-255t96-230 150-194 195-150 229-97T960 0q133 0 255 34t230 96 194 150 150 195 97 229 34 256q0 133-34 255t-96 230-150 194-195 150-229 97-256 34zm0-1792q-115 0-221 30t-198 84-169 130-130 168-84 199-30 221q0 114 30 220t84 199 130 169 168 130 199 84 221 30q114 0 220-30t199-84 169-130 130-168 84-199 30-221q0-114-30-220t-84-199-130-169-168-130-199-84-221-30zm-64 640h128v640H896V768zm0-256h128v128H896V512z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 581 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 0H14.4L14.7 0.2L14.9 0.5C14.9524 0.570883 14.9885 0.652432 15.0058 0.738849C15.023 0.825265 15.0211 0.914429 15 1V14H2.8L0.999997 12.2V1C0.985033 0.85904 1.02046 0.717335 1.1 0.6L1.3 0.3L1.6 0.1H14V0ZM14 1H13V7H3V1H2V11.8L3.2 13H4V9H11V13H14V1ZM4 6H12V1H4V6ZM10 10H5V13H6V11H7V13H10V10Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 421 B |
@@ -2,14 +2,14 @@
|
||||
"name": "arc",
|
||||
"displayName": "%arc.displayName%",
|
||||
"description": "%arc.description%",
|
||||
"version": "0.6.3",
|
||||
"version": "0.5.1",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||
"icon": "images/extension.png",
|
||||
"engines": {
|
||||
"vscode": "*",
|
||||
"azdata": ">=1.23.0"
|
||||
"azdata": ">=1.22.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"onCommand:arc.connectToController",
|
||||
@@ -136,7 +136,10 @@
|
||||
"displayName": "%resource.type.azure.arc.display.name%",
|
||||
"description": "%resource.type.azure.arc.description%",
|
||||
"platforms": "*",
|
||||
"icon": "./images/data_controller.svg",
|
||||
"icon": {
|
||||
"light": "./images/data_controller.svg",
|
||||
"dark": "./images/data_controller.svg"
|
||||
},
|
||||
"tags": ["Hybrid", "SQL Server", "PostgreSQL"],
|
||||
"providers": [
|
||||
{
|
||||
@@ -509,7 +512,10 @@
|
||||
"displayName": "%resource.type.arc.sql.display.name%",
|
||||
"description": "%resource.type.arc.sql.description%",
|
||||
"platforms": "*",
|
||||
"icon": "./images/miaa.svg",
|
||||
"icon": {
|
||||
"light": "./images/miaa.svg",
|
||||
"dark": "./images/miaa.svg"
|
||||
},
|
||||
"tags": ["Hybrid", "SQL Server"],
|
||||
"providers": [
|
||||
{
|
||||
@@ -558,6 +564,7 @@
|
||||
"variableName": "AZDATA_NB_VAR_SQL_INSTANCE_NAME",
|
||||
"type": "text",
|
||||
"defaultValue": "sqlinstance1",
|
||||
"description": "%arc.sql.invalid.instance.name%",
|
||||
"required": true,
|
||||
"textValidationRequired": true,
|
||||
"textValidationRegex": "^[a-z]([-a-z0-9]{0,11}[a-z0-9])?$",
|
||||
@@ -567,6 +574,7 @@
|
||||
"label": "%arc.sql.username%",
|
||||
"variableName": "AZDATA_NB_VAR_SQL_USERNAME",
|
||||
"type": "text",
|
||||
"description": "%arc.sql.invalid.username%",
|
||||
"required": true,
|
||||
"textValidationRequired": true,
|
||||
"textValidationRegex": "^(?!sa$)",
|
||||
@@ -670,7 +678,10 @@
|
||||
"displayName": "%resource.type.arc.postgres.display.name%",
|
||||
"description": "%resource.type.arc.postgres.description%",
|
||||
"platforms": "*",
|
||||
"icon": "./images/postgres.svg",
|
||||
"icon": {
|
||||
"light": "./images/postgres.svg",
|
||||
"dark": "./images/postgres.svg"
|
||||
},
|
||||
"tags": ["Hybrid", "PostgreSQL"],
|
||||
"providers": [
|
||||
{
|
||||
|
||||
@@ -218,63 +218,6 @@ export function createCredentialId(controllerId: string, resourceType: string, i
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the gibibyte (GiB) conversion of a quantity that could currently be represented by a range
|
||||
* of SI suffixes (E, P, T, G, M, K, m) or their power-of-two equivalents (Ei, Pi, Ti, Gi, Mi, Ki)
|
||||
* @param value The string of a quantity to be converted
|
||||
* @returns String of GiB conversion
|
||||
*/
|
||||
export function convertToGibibyteString(value: string): string {
|
||||
if (!value) {
|
||||
throw new Error(`Value provided is not a valid Kubernetes resource quantity`);
|
||||
}
|
||||
|
||||
let base10ToBase2Multiplier;
|
||||
let floatValue = parseFloat(value);
|
||||
let splitValue = value.split(String(floatValue));
|
||||
let unit = splitValue[1];
|
||||
|
||||
if (unit === 'K') {
|
||||
base10ToBase2Multiplier = 1000 / 1024;
|
||||
floatValue = (floatValue * base10ToBase2Multiplier) / Math.pow(1024, 2);
|
||||
} else if (unit === 'M') {
|
||||
base10ToBase2Multiplier = Math.pow(1000, 2) / Math.pow(1024, 2);
|
||||
floatValue = (floatValue * base10ToBase2Multiplier) / 1024;
|
||||
} else if (unit === 'G') {
|
||||
base10ToBase2Multiplier = Math.pow(1000, 3) / Math.pow(1024, 3);
|
||||
floatValue = floatValue * base10ToBase2Multiplier;
|
||||
} else if (unit === 'T') {
|
||||
base10ToBase2Multiplier = Math.pow(1000, 4) / Math.pow(1024, 4);
|
||||
floatValue = (floatValue * base10ToBase2Multiplier) * 1024;
|
||||
} else if (unit === 'P') {
|
||||
base10ToBase2Multiplier = Math.pow(1000, 5) / Math.pow(1024, 5);
|
||||
floatValue = (floatValue * base10ToBase2Multiplier) * Math.pow(1024, 2);
|
||||
} else if (unit === 'E') {
|
||||
base10ToBase2Multiplier = Math.pow(1000, 6) / Math.pow(1024, 6);
|
||||
floatValue = (floatValue * base10ToBase2Multiplier) * Math.pow(1024, 3);
|
||||
} else if (unit === 'm') {
|
||||
floatValue = (floatValue / 1000) / Math.pow(1024, 3);
|
||||
} else if (unit === '') {
|
||||
floatValue = floatValue / Math.pow(1024, 3);
|
||||
} else if (unit === 'Ki') {
|
||||
floatValue = floatValue / Math.pow(1024, 2);
|
||||
} else if (unit === 'Mi') {
|
||||
floatValue = floatValue / 1024;
|
||||
} else if (unit === 'Gi') {
|
||||
floatValue = floatValue;
|
||||
} else if (unit === 'Ti') {
|
||||
floatValue = floatValue * 1024;
|
||||
} else if (unit === 'Pi') {
|
||||
floatValue = floatValue * Math.pow(1024, 2);
|
||||
} else if (unit === 'Ei') {
|
||||
floatValue = floatValue * Math.pow(1024, 3);
|
||||
} else {
|
||||
throw new Error(`${value} is not a valid Kubernetes resource quantity`);
|
||||
}
|
||||
|
||||
return String(floatValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Throws an Error with given {@link message} unless {@link condition} is true.
|
||||
* This also tells the typescript compiler that the condition is 'truthy' in the remainder of the scope
|
||||
* where this function was called.
|
||||
|
||||
@@ -40,10 +40,7 @@ export class IconPathHelper {
|
||||
public static controller: IconPath;
|
||||
public static health: IconPath;
|
||||
public static success: IconPath;
|
||||
public static save: IconPath;
|
||||
public static discard: IconPath;
|
||||
public static fail: IconPath;
|
||||
public static information: IconPath;
|
||||
|
||||
public static setExtensionContext(context: vscode.ExtensionContext) {
|
||||
IconPathHelper.context = context;
|
||||
@@ -119,22 +116,10 @@ export class IconPathHelper {
|
||||
light: context.asAbsolutePath('images/success.svg'),
|
||||
dark: context.asAbsolutePath('images/success.svg'),
|
||||
};
|
||||
IconPathHelper.save = {
|
||||
light: context.asAbsolutePath('images/save.svg'),
|
||||
dark: context.asAbsolutePath('images/save.svg'),
|
||||
};
|
||||
IconPathHelper.discard = {
|
||||
light: context.asAbsolutePath('images/discard.svg'),
|
||||
dark: context.asAbsolutePath('images/discard.svg'),
|
||||
};
|
||||
IconPathHelper.fail = {
|
||||
light: context.asAbsolutePath('images/fail.svg'),
|
||||
dark: context.asAbsolutePath('images/fail.svg'),
|
||||
};
|
||||
IconPathHelper.information = {
|
||||
light: context.asAbsolutePath('images/information.svg'),
|
||||
dark: context.asAbsolutePath('images/information.svg'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,6 @@ export const resourceHealth = localize('arc.resourceHealth', "Resource health");
|
||||
|
||||
export const newInstance = localize('arc.createNew', "New Instance");
|
||||
export const deleteText = localize('arc.delete', "Delete");
|
||||
export const saveText = localize('arc.save', "Save");
|
||||
export const discardText = localize('arc.discard', "Discard");
|
||||
export const resetPassword = localize('arc.resetPassword', "Reset Password");
|
||||
export const openInAzurePortal = localize('arc.openInAzurePortal', "Open in Azure Portal");
|
||||
export const resourceGroup = localize('arc.resourceGroup', "Resource Group");
|
||||
@@ -61,10 +59,6 @@ export const yes = localize('arc.yes', "Yes");
|
||||
export const no = localize('arc.no', "No");
|
||||
export const feedback = localize('arc.feedback', "Feedback");
|
||||
export const selectConnectionString = localize('arc.selectConnectionString', "Select from available client connection strings below.");
|
||||
export const addingWokerNodes = localize('arc.addingWokerNodes', "adding worker nodes");
|
||||
export const workerNodesDescription = localize('arc.workerNodesDescription', "Expand your server group and scale your database by adding worker nodes.");
|
||||
export const configurationInformation = localize('arc.configurationInformation', "You can configure the number of CPU cores and storage size that will apply to both worker nodes and coordinator node. Each worker node will have the same configuration. Adjust the number of CPU cores and memory settings for your server group.");
|
||||
export const workerNodesInformation = localize('arc.workerNodeInformation', "In preview it is not possible to reduce the number of worker nodes. Please refer to documentation linked above for more information.");
|
||||
export const vCores = localize('arc.vCores', "vCores");
|
||||
export const ram = localize('arc.ram', "RAM");
|
||||
export const refresh = localize('arc.refresh', "Refresh");
|
||||
@@ -120,27 +114,9 @@ export const databaseName = localize('arc.databaseName', "Database name");
|
||||
export const enterNewPassword = localize('arc.enterNewPassword', "Enter a new password");
|
||||
export const confirmNewPassword = localize('arc.confirmNewPassword', "Confirm the new password");
|
||||
export const learnAboutPostgresClients = localize('arc.learnAboutPostgresClients', "Learn more about Azure PostgreSQL Hyperscale client interfaces");
|
||||
export const scalingCompute = localize('arc.scalingCompute', "scaling compute vCores and memory.");
|
||||
export const computeAndStorageDescriptionPartOne = localize('arc.computeAndStorageDescriptionPartOne', "You can scale your Azure Arc enabled");
|
||||
export const computeAndStorageDescriptionPartTwo = localize('arc.computeAndStorageDescriptionPartTwo', "PostgreSQL Hyperscale server group by");
|
||||
export const computeAndStorageDescriptionPartThree = localize('arc.computeAndStorageDescriptionPartThree', "without downtime and by");
|
||||
export const computeAndStorageDescriptionPartFour = localize('arc.computeAndStorageDescriptionPartFour', "Before doing so, you need to ensure");
|
||||
export const computeAndStorageDescriptionPartFive = localize('arc.computeAndStorageDescriptionPartFive', "there are sufficient resources available");
|
||||
export const computeAndStorageDescriptionPartSix = localize('arc.computeAndStorageDescriptionPartSix', "in your Kubernetes cluster to honor this configuration.");
|
||||
export const node = localize('arc.node', "node");
|
||||
export const nodes = localize('arc.nodes', "nodes");
|
||||
export const workerNodes = localize('arc.workerNodes', "Worker Nodes");
|
||||
export const storagePerNode = localize('arc.storagePerNode', "storage per node");
|
||||
export const workerNodeCount = localize('arc.workerNodeCount', "Worker node count:");
|
||||
export const configurationPerNode = localize('arc.configurationPerNode', "Configuration (per node)");
|
||||
export const coresLimit = localize('arc.coresLimit', "CPU limit:");
|
||||
export const coresRequest = localize('arc.coresRequest', "CPU request:");
|
||||
export const memoryLimit = localize('arc.memoryLimit', "Memory limit (in GB):");
|
||||
export const memoryRequest = localize('arc.memoryRequest', "Memory request (in GB):");
|
||||
export const workerValidationErrorMessage = localize('arc.workerValidationErrorMessage', "The number of workers cannot be decreased.");
|
||||
export const coresValidationErrorMessage = localize('arc.coresValidationErrorMessage', "Valid CPU resource quantities are strictly positive.");
|
||||
export const memoryRequestValidationErrorMessage = localize('arc.memoryRequestValidationErrorMessage', "Memory request must be at least 0.25Gib");
|
||||
export const memoryLimitValidationErrorMessage = localize('arc.memoryLimitValidationErrorMessage', "Memory limit must be at least 0.25Gib");
|
||||
export const arcResources = localize('arc.arcResources', "Azure Arc Resources");
|
||||
export const enterANonEmptyPassword = localize('arc.enterANonEmptyPassword', "Enter a non empty password or press escape to exit.");
|
||||
export const thePasswordsDoNotMatch = localize('arc.thePasswordsDoNotMatch', "The passwords do not match. Confirm the password or press escape to exit.");
|
||||
@@ -154,9 +130,7 @@ export const podsReady = localize('arc.podsReady', "pods ready");
|
||||
|
||||
export function databaseCreated(name: string): string { return localize('arc.databaseCreated', "Database {0} created", name); }
|
||||
export function deletingInstance(name: string): string { return localize('arc.deletingInstance', "Deleting instance '{0}'...", name); }
|
||||
export function updatingInstance(name: string): string { return localize('arc.updatingInstance', "Updating instance '{0}'...", name); }
|
||||
export function instanceDeleted(name: string): string { return localize('arc.instanceDeleted', "Instance '{0}' deleted", name); }
|
||||
export function instanceUpdated(name: string): string { return localize('arc.instanceUpdated', "Instance '{0}' updated", name); }
|
||||
export function copiedToClipboard(name: string): string { return localize('arc.copiedToClipboard', "{0} copied to clipboard", name); }
|
||||
export function clickTheTroubleshootButton(resourceType: string): string { return localize('arc.clickTheTroubleshootButton', "Click the troubleshoot button to open the Azure Arc {0} troubleshooting notebook.", resourceType); }
|
||||
export function numVCores(vCores: string | undefined): string {
|
||||
@@ -178,8 +152,6 @@ export const couldNotFindControllerRegistration = localize('arc.couldNotFindCont
|
||||
export function refreshFailed(error: any): string { return localize('arc.refreshFailed', "Refresh failed. {0}", getErrorMessage(error)); }
|
||||
export function openDashboardFailed(error: any): string { return localize('arc.openDashboardFailed', "Error opening dashboard. {0}", getErrorMessage(error)); }
|
||||
export function instanceDeletionFailed(name: string, error: any): string { return localize('arc.instanceDeletionFailed', "Failed to delete instance {0}. {1}", name, getErrorMessage(error)); }
|
||||
export function instanceUpdateFailed(name: string, error: any): string { return localize('arc.instanceUpdateFailed', "Failed to update instance {0}. {1}", name, getErrorMessage(error)); }
|
||||
export function pageDiscardFailed(error: any): string { return localize('arc.pageDiscardFailed', "Failed to discard user input. {0}", getErrorMessage(error)); }
|
||||
export function databaseCreationFailed(name: string, error: any): string { return localize('arc.databaseCreationFailed', "Failed to create database {0}. {1}", name, getErrorMessage(error)); }
|
||||
export function connectToControllerFailed(url: string, error: any): string { return localize('arc.connectToControllerFailed', "Could not connect to controller {0}. {1}", url, getErrorMessage(error)); }
|
||||
export function connectToSqlFailed(serverName: string, error: any): string { return localize('arc.connectToSqlFailed', "Could not connect to SQL managed instance - Azure Arc Instance {0}. {1}", serverName, getErrorMessage(error)); }
|
||||
|
||||
@@ -9,7 +9,6 @@ import * as vscode from 'vscode';
|
||||
import * as loc from '../localizedConstants';
|
||||
import { ControllerModel, Registration } from './controllerModel';
|
||||
import { ResourceModel } from './resourceModel';
|
||||
import { Deferred } from '../common/promise';
|
||||
import { parseIpAndPort } from '../common/utils';
|
||||
|
||||
export class PostgresModel extends ResourceModel {
|
||||
@@ -20,8 +19,6 @@ export class PostgresModel extends ResourceModel {
|
||||
public onConfigUpdated = this._onConfigUpdated.event;
|
||||
public configLastUpdated?: Date;
|
||||
|
||||
private _refreshPromise?: Deferred<void>;
|
||||
|
||||
constructor(private _controllerModel: ControllerModel, info: ResourceInfo, registration: Registration) {
|
||||
super(info, registration);
|
||||
this._azdataApi = <azdataExt.IExtension>vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
|
||||
@@ -58,10 +55,7 @@ export class PostgresModel extends ResourceModel {
|
||||
const cpuRequest = this._config.spec.scheduling?.default?.resources?.requests?.cpu;
|
||||
const ramRequest = this._config.spec.scheduling?.default?.resources?.requests?.memory;
|
||||
const storage = this._config.spec.storage?.data?.size;
|
||||
|
||||
// scale.shards was renamed to scale.workers. Check both for backwards compatibility.
|
||||
const scale = this._config.spec.scale;
|
||||
const nodes = (scale?.workers ?? scale?.shards ?? 0) + 1; // An extra node for the coordinator
|
||||
const nodes = (this._config.spec.scale?.shards ?? 0) + 1; // An extra node for the coordinator
|
||||
|
||||
let configuration: string[] = [];
|
||||
configuration.push(`${nodes} ${nodes > 1 ? loc.nodes : loc.node}`);
|
||||
@@ -84,23 +78,9 @@ export class PostgresModel extends ResourceModel {
|
||||
|
||||
/** Refreshes the model */
|
||||
public async refresh() {
|
||||
// Only allow one refresh to be happening at a time
|
||||
if (this._refreshPromise) {
|
||||
return this._refreshPromise.promise;
|
||||
}
|
||||
this._refreshPromise = new Deferred();
|
||||
|
||||
try {
|
||||
await this._controllerModel.azdataLogin();
|
||||
this._config = (await this._azdataApi.azdata.arc.postgres.server.show(this.info.name)).result;
|
||||
this.configLastUpdated = new Date();
|
||||
this._onConfigUpdated.fire(this._config);
|
||||
this._refreshPromise.resolve();
|
||||
} catch (err) {
|
||||
this._refreshPromise.reject(err);
|
||||
throw err;
|
||||
} finally {
|
||||
this._refreshPromise = undefined;
|
||||
}
|
||||
await this._controllerModel.azdataLogin();
|
||||
this._config = (await this._azdataApi.azdata.arc.postgres.server.show(this.info.name)).result;
|
||||
this.configLastUpdated = new Date();
|
||||
this._onConfigUpdated.fire(this._config);
|
||||
}
|
||||
}
|
||||
|
||||
2
extensions/arc/src/test/.gitignore
vendored
Normal file
2
extensions/arc/src/test/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/env
|
||||
/__pycache__
|
||||
21
extensions/arc/src/test/README.md
Normal file
21
extensions/arc/src/test/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Tests for deploying Arc resources via Jupyter notebook
|
||||
|
||||
## Prerequisites
|
||||
- Python >= 3.6
|
||||
- Pip package manager
|
||||
- Azdata CLI installed and logged into an Arc controller
|
||||
|
||||
## Running the tests
|
||||
### 1. (Optional, recommended) Create and activate a Python virtual environment
|
||||
- `python -m venv env`
|
||||
- `source env/bin/activate` (Linux)
|
||||
- `env\Scripts\activate.bat` (Windows)
|
||||
|
||||
### 2. Upgrade pip
|
||||
- `pip install --upgrade pip`
|
||||
|
||||
### 3. Install the dependencies
|
||||
- `pip install -r requirements.txt`
|
||||
|
||||
### 4. Run the tests
|
||||
- `pytest`
|
||||
@@ -7,7 +7,7 @@ import { ResourceType } from 'arc';
|
||||
import 'mocha';
|
||||
import * as should from 'should';
|
||||
import * as vscode from 'vscode';
|
||||
import { getAzurecoreApi, getConnectionModeDisplayText, getDatabaseStateDisplayText, getErrorMessage, getResourceTypeIcon, parseEndpoint, parseIpAndPort, promptAndConfirmPassword, promptForInstanceDeletion, resourceTypeToDisplayName, convertToGibibyteString } from '../../common/utils';
|
||||
import { getAzurecoreApi, getConnectionModeDisplayText, getDatabaseStateDisplayText, getErrorMessage, getResourceTypeIcon, parseEndpoint, parseIpAndPort, promptAndConfirmPassword, promptForInstanceDeletion, resourceTypeToDisplayName } from '../../common/utils';
|
||||
import { ConnectionMode as ConnectionMode, IconPathHelper } from '../../constants';
|
||||
import * as loc from '../../localizedConstants';
|
||||
import { MockInputBox } from '../stubs';
|
||||
@@ -254,116 +254,3 @@ describe('parseIpAndPort', function (): void {
|
||||
should(() => parseIpAndPort(ip)).throwError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertToGibibyteString Method Tests', function () {
|
||||
const tolerance = 0.001;
|
||||
it('Value is in KB', function (): void {
|
||||
const value = '44000K';
|
||||
const conversion = 0.04097819;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in MB', function (): void {
|
||||
const value = '1100M';
|
||||
const conversion = 1.02445483;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in GB', function (): void {
|
||||
const value = '1G';
|
||||
const conversion = 0.931322575;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in TB', function (): void {
|
||||
const value = '1T';
|
||||
const conversion = 931.32257;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in PB', function (): void {
|
||||
const value = '0.1P';
|
||||
const conversion = 93132.25746;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in EB', function (): void {
|
||||
const value = '1E';
|
||||
const conversion = 931322574.6154;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in mB', function (): void {
|
||||
const value = '1073741824000m';
|
||||
const conversion = 1;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in B', function (): void {
|
||||
const value = '1073741824';
|
||||
const conversion = 1;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in KiB', function (): void {
|
||||
const value = '1048576Ki';
|
||||
const conversion = 1;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in MiB', function (): void {
|
||||
const value = '256Mi';
|
||||
const conversion = 0.25;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in GiB', function (): void {
|
||||
const value = '1000Gi';
|
||||
const conversion = 1000;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in TiB', function (): void {
|
||||
const value = '1Ti';
|
||||
const conversion = 1024;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in PiB', function (): void {
|
||||
const value = '1Pi';
|
||||
const conversion = 1048576;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is in EiB', function (): void {
|
||||
const value = '1Ei';
|
||||
const conversion = 1073741824;
|
||||
const check = Math.abs(conversion - parseFloat(convertToGibibyteString(value)));
|
||||
should(check).lessThanOrEqual(tolerance);
|
||||
});
|
||||
|
||||
it('Value is empty', function (): void {
|
||||
const value = '';
|
||||
const error = new Error(`Value provided is not a valid Kubernetes resource quantity`);
|
||||
should(() => convertToGibibyteString(value)).throwError(error);
|
||||
});
|
||||
|
||||
it('Value is not a valid Kubernetes resource quantity', function (): void {
|
||||
const value = '1J';
|
||||
const error = new Error(`${value} is not a valid Kubernetes resource quantity`);
|
||||
should(() => convertToGibibyteString(value)).throwError(error);
|
||||
});
|
||||
});
|
||||
|
||||
2
extensions/arc/src/test/requirements.txt
Normal file
2
extensions/arc/src/test/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pytest==5.3.5
|
||||
notebook==6.0.3
|
||||
111
extensions/arc/src/test/test_notebooks.py
Normal file
111
extensions/arc/src/test/test_notebooks.py
Normal file
@@ -0,0 +1,111 @@
|
||||
##---------------------------------------------------------------------------------------------
|
||||
## Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
## Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
##--------------------------------------------------------------------------------------------
|
||||
|
||||
import json
|
||||
import nbformat
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
import uuid
|
||||
from nbconvert.preprocessors import ExecutePreprocessor
|
||||
from subprocess import Popen, PIPE, TimeoutExpired
|
||||
|
||||
## Variables
|
||||
notebook_path = '../../notebooks/arcDeployment/'
|
||||
|
||||
## Helper functions
|
||||
def generate_name(prefix, length=8):
|
||||
return (prefix + '-' + ''.join(
|
||||
[random.choice(string.ascii_lowercase)
|
||||
for n in range(length - len(prefix) - 1)]))
|
||||
|
||||
def clear_env():
|
||||
for k in [k for k in os.environ.keys() if k.startswith('AZDATA_NB_VAR_')]:
|
||||
del os.environ[k]
|
||||
|
||||
def azdata(commands, timeout=None, stdin=None):
|
||||
commands.insert(0, "azdata")
|
||||
print('Executing command: \n', ' '.join(commands))
|
||||
proc = Popen(commands, stdin=PIPE if stdin is not None else None, stdout=PIPE, stderr=PIPE, shell=os.name=='nt')
|
||||
try:
|
||||
(stdout, stderr) = proc.communicate(input=stdin, timeout=timeout)
|
||||
except TimeoutExpired:
|
||||
# https://docs.python.org/3.5/library/subprocess.html#subprocess.Popen.communicate
|
||||
# The child process is not killed if the timeout expires, so in order to
|
||||
# cleanup properly we should kill the child process and finish communication.
|
||||
proc.kill()
|
||||
(stdout, stderr) = proc.communicate(timeout=timeout)
|
||||
sys.stdout.buffer.write(stdout)
|
||||
sys.stderr.buffer.write(stderr)
|
||||
raise
|
||||
|
||||
sys.stdout.buffer.write(stdout)
|
||||
if proc.returncode != 0:
|
||||
raise Exception(stderr)
|
||||
else:
|
||||
sys.stderr.buffer.write(stderr)
|
||||
|
||||
return (stdout.decode(sys.stdout.encoding),
|
||||
stderr.decode(sys.stderr.encoding))
|
||||
|
||||
## Tests
|
||||
def test_postgres_create():
|
||||
# Load the notebook
|
||||
with open(notebook_path + 'deploy.postgres.existing.arc.ipynb') as f:
|
||||
nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)
|
||||
|
||||
name = generate_name('pg')
|
||||
try:
|
||||
# Setup the environment
|
||||
os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAME'] = name
|
||||
subscription = os.environ['AZDATA_NB_VAR_ARC_SUBSCRIPTION'] = str(uuid.uuid4())
|
||||
resource_group = os.environ['AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME'] = 'test'
|
||||
namespace = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAMESPACE'] = 'default'
|
||||
workers = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_WORKERS'] = '1'
|
||||
service_type = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_SERVICE_TYPE'] = 'NodePort'
|
||||
data_size = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_DATA_SIZE'] = '512'
|
||||
port = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_PORT'] = '5431'
|
||||
extensions = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_EXTENSIONS'] = 'pg_cron,postgis'
|
||||
cpu_min = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MIN'] = '1'
|
||||
cpu_max = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MAX'] = '2'
|
||||
memory_min = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MIN'] = '256'
|
||||
memory_max = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MAX'] = '1023'
|
||||
backup_sizes = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_SIZES'] = '512,1023'
|
||||
backup_full_interval = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_FULL_INTERVAL'] = '20'
|
||||
backup_delta_interval = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_DELTA_INTERVAL'] = '10'
|
||||
backup_retention_min = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MIN'] = '1,1GB;2,2GB'
|
||||
backup_retention_max = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MAX'] = '2,2GB;3,3GB'
|
||||
|
||||
# Execute the notebook that creates Postgres
|
||||
ExecutePreprocessor(timeout=1200).preprocess(nb, {'metadata': {'path': notebook_path}})
|
||||
|
||||
# Verify that Postgres was created successfully
|
||||
(out, _) = azdata(['postgres', 'server', 'show', '-n', name])
|
||||
db = json.loads(out)
|
||||
assert db['metadata']['name'] == name
|
||||
assert db['metadata']['namespace'] == namespace
|
||||
assert db['spec']['scale']['shards'] == int(workers)
|
||||
assert db['spec']['service']['type'] == service_type
|
||||
assert db['spec']['storage']['volumeSize'] == data_size + 'Mi'
|
||||
assert db['spec']['service']['port'] == int(port)
|
||||
assert [p['name'] for p in db['spec']['engine']['plugins']] == ['pg_cron' ,'postgis']
|
||||
assert db['spec']['scheduling']['default']['resources']['requests']['cpu'] == cpu_min
|
||||
assert db['spec']['scheduling']['default']['resources']['limits']['cpu'] == cpu_max
|
||||
assert db['spec']['scheduling']['default']['resources']['requests']['memory'] == memory_min + 'Mi'
|
||||
assert db['spec']['scheduling']['default']['resources']['limits']['memory'] == memory_max + 'Mi'
|
||||
assert [t['storage']['volumeSize'] for t in db['spec']['backups']['tiers']] == [b + 'Mi' for b in backup_sizes.split(',')]
|
||||
assert db['spec']['backups']['fullMinutes'] == int(backup_full_interval)
|
||||
assert db['spec']['backups']['deltaMinutes'] == int(backup_delta_interval)
|
||||
for i in range(len(db['spec']['backups']['tiers'])):
|
||||
assert db['spec']['backups']['tiers'][i]['retention']['minimums'] == backup_retention_min.split(';')[i].split(',')
|
||||
assert db['spec']['backups']['tiers'][i]['retention']['maximums'] == backup_retention_max.split(';')[i].split(',')
|
||||
except Exception:
|
||||
# Capture cell outputs to help with debugging
|
||||
print([c['outputs'] for c in nb['cells'] if c.get('outputs')])
|
||||
raise
|
||||
finally:
|
||||
clear_env()
|
||||
azdata(['postgres', 'server', 'delete', '-n', name])
|
||||
@@ -91,7 +91,8 @@ export class MiaaConnectionStringsPage extends DashboardPage {
|
||||
$serverName = "${externalEndpoint.ip},${externalEndpoint.port}";
|
||||
$conn = sqlsrv_connect($serverName, $connectionInfo);`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Python', `dbname='master' user='${username}' host='${externalEndpoint.ip}' password='{your_password_here}' port='${externalEndpoint.port}' sslmode='true'`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Ruby', `host=${externalEndpoint.ip}; user=${username} password={your_password_here} port=${externalEndpoint.port} sslmode=require`)
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Ruby', `host=${externalEndpoint.ip}; user=${username} password={your_password_here} port=${externalEndpoint.port} sslmode=require`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Web App', `Database=master; Data Source=${externalEndpoint.ip}; User Id=${username}; Password={your_password_here}`)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,489 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as azdataExt from 'azdata-ext';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper, cssStyles } from '../../../constants';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
import { convertToGibibyteString } from '../../../common/utils';
|
||||
|
||||
export class PostgresComputeAndStoragePage extends DashboardPage {
|
||||
private workerContainer?: azdata.DivContainer;
|
||||
|
||||
private workerBox?: azdata.InputBoxComponent;
|
||||
private coresLimitBox?: azdata.InputBoxComponent;
|
||||
private coresRequestBox?: azdata.InputBoxComponent;
|
||||
private memoryLimitBox?: azdata.InputBoxComponent;
|
||||
private memoryRequestBox?: azdata.InputBoxComponent;
|
||||
|
||||
private discardButton?: azdata.ButtonComponent;
|
||||
private saveButton?: azdata.ButtonComponent;
|
||||
|
||||
private saveArgs: {
|
||||
workers?: number,
|
||||
coresLimit?: string,
|
||||
coresRequest?: string,
|
||||
memoryLimit?: string,
|
||||
memoryRequest?: string
|
||||
} = {};
|
||||
|
||||
private readonly _azdataApi: azdataExt.IExtension;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
|
||||
|
||||
this.initializeConfigurationBoxes();
|
||||
|
||||
this.disposables.push(this._postgresModel.onConfigUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.handleServiceUpdated())));
|
||||
}
|
||||
|
||||
protected get title(): string {
|
||||
return loc.computeAndStorage;
|
||||
}
|
||||
|
||||
protected get id(): string {
|
||||
return 'postgres-compute-and-storage';
|
||||
}
|
||||
|
||||
protected get icon(): { dark: string; light: string; } {
|
||||
return IconPathHelper.computeStorage;
|
||||
}
|
||||
|
||||
protected get container(): azdata.Component {
|
||||
const root = this.modelView.modelBuilder.divContainer().component();
|
||||
const content = this.modelView.modelBuilder.divContainer().component();
|
||||
root.addItem(content, { CSSStyles: { 'margin': '20px' } });
|
||||
|
||||
content.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorage,
|
||||
CSSStyles: { ...cssStyles.title }
|
||||
}).component());
|
||||
|
||||
const infoComputeStorage_p1 = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorageDescriptionPartOne,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const infoComputeStorage_p2 = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorageDescriptionPartTwo,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const workerNodeslink = this.modelView.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({
|
||||
label: loc.addingWokerNodes,
|
||||
url: 'https://docs.microsoft.com/azure/azure-arc/data/scale-up-down-postgresql-hyperscale-server-group-using-cli',
|
||||
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const infoComputeStorage_p3 = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorageDescriptionPartThree,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const memoryVCoreslink = this.modelView.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({
|
||||
label: loc.scalingCompute,
|
||||
url: 'https://docs.microsoft.com/azure/azure-arc/data/scale-up-down-postgresql-hyperscale-server-group-using-cli',
|
||||
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const infoComputeStorage_p4 = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorageDescriptionPartFour,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const infoComputeStorage_p5 = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorageDescriptionPartFive,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const infoComputeStorage_p6 = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.computeAndStorageDescriptionPartSix,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const computeInfoAndLinks = this.modelView.modelBuilder.flexContainer().withLayout({ flexWrap: 'wrap' }).component();
|
||||
computeInfoAndLinks.addItem(infoComputeStorage_p1, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(infoComputeStorage_p2, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(workerNodeslink, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(infoComputeStorage_p3, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(memoryVCoreslink, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(infoComputeStorage_p4, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(infoComputeStorage_p5, { CSSStyles: { 'margin-right': '5px' } });
|
||||
computeInfoAndLinks.addItem(infoComputeStorage_p6, { CSSStyles: { 'margin-right': '5px' } });
|
||||
content.addItem(computeInfoAndLinks, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
content.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.workerNodes,
|
||||
CSSStyles: { ...cssStyles.title, 'margin-top': '25px' }
|
||||
}).component());
|
||||
|
||||
this.workerContainer = this.modelView.modelBuilder.divContainer().component();
|
||||
this.workerContainer.addItems(this.createUserInputSection(), { CSSStyles: { 'min-height': '30px' } });
|
||||
content.addItem(this.workerContainer, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
protected get toolbarContainer(): azdata.ToolbarContainer {
|
||||
// Save Edits
|
||||
this.saveButton = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
label: loc.saveText,
|
||||
iconPath: IconPathHelper.save,
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.saveButton.onDidClick(async () => {
|
||||
this.saveButton!.enabled = false;
|
||||
try {
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.updatingInstance(this._postgresModel.info.name),
|
||||
cancellable: false
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
await this._azdataApi.azdata.arc.postgres.server.edit(
|
||||
this._postgresModel.info.name, this.saveArgs);
|
||||
await this._postgresModel.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
vscode.window.showInformationMessage(loc.instanceUpdated(this._postgresModel.info.name));
|
||||
|
||||
this.discardButton!.enabled = false;
|
||||
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.instanceUpdateFailed(this._postgresModel.info.name, error));
|
||||
}
|
||||
}));
|
||||
|
||||
// Discard
|
||||
this.discardButton = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
label: loc.discardText,
|
||||
iconPath: IconPathHelper.discard,
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.discardButton.onDidClick(async () => {
|
||||
this.discardButton!.enabled = false;
|
||||
try {
|
||||
this.editWorkerNodeCount();
|
||||
this.editCores();
|
||||
this.editMemory();
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.pageDiscardFailed(error));
|
||||
} finally {
|
||||
this.saveButton!.enabled = false;
|
||||
}
|
||||
}));
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems([
|
||||
{ component: this.saveButton },
|
||||
{ component: this.discardButton }
|
||||
]).component();
|
||||
}
|
||||
|
||||
private initializeConfigurationBoxes() {
|
||||
this.workerBox = this.modelView.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
readOnly: false,
|
||||
validationErrorMessage: loc.workerValidationErrorMessage,
|
||||
inputType: 'number',
|
||||
placeHolder: loc.loading
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.workerBox.onTextChanged(() => {
|
||||
if (!(this.handleOnTextChanged(this.workerBox!))) {
|
||||
this.saveArgs.workers = undefined;
|
||||
} else {
|
||||
this.saveArgs.workers = parseInt(this.workerBox!.value!);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.coresLimitBox = this.modelView.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
readOnly: false,
|
||||
min: 1,
|
||||
validationErrorMessage: loc.coresValidationErrorMessage,
|
||||
inputType: 'number',
|
||||
placeHolder: loc.loading
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.coresLimitBox.onTextChanged(() => {
|
||||
if (!(this.handleOnTextChanged(this.coresLimitBox!))) {
|
||||
this.saveArgs.coresLimit = undefined;
|
||||
} else {
|
||||
this.saveArgs.coresLimit = this.coresLimitBox!.value;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.coresRequestBox = this.modelView.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
readOnly: false,
|
||||
min: 1,
|
||||
validationErrorMessage: loc.coresValidationErrorMessage,
|
||||
inputType: 'number',
|
||||
placeHolder: loc.loading
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.coresRequestBox.onTextChanged(() => {
|
||||
if (!(this.handleOnTextChanged(this.coresRequestBox!))) {
|
||||
this.saveArgs.coresRequest = undefined;
|
||||
} else {
|
||||
this.saveArgs.coresRequest = this.coresRequestBox!.value;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.memoryLimitBox = this.modelView.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
readOnly: false,
|
||||
min: 0.25,
|
||||
validationErrorMessage: loc.memoryLimitValidationErrorMessage,
|
||||
inputType: 'number',
|
||||
placeHolder: loc.loading
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.memoryLimitBox.onTextChanged(() => {
|
||||
if (!(this.handleOnTextChanged(this.memoryLimitBox!))) {
|
||||
this.saveArgs.memoryLimit = undefined;
|
||||
} else {
|
||||
this.saveArgs.memoryLimit = this.memoryLimitBox!.value + 'Gi';
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.memoryRequestBox = this.modelView.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
readOnly: false,
|
||||
min: 0.25,
|
||||
validationErrorMessage: loc.memoryRequestValidationErrorMessage,
|
||||
inputType: 'number',
|
||||
placeHolder: loc.loading
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.memoryRequestBox.onTextChanged(() => {
|
||||
if (!(this.handleOnTextChanged(this.memoryRequestBox!))) {
|
||||
this.saveArgs.memoryRequest = undefined;
|
||||
} else {
|
||||
this.saveArgs.memoryRequest = this.memoryRequestBox!.value + 'Gi';
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private createUserInputSection(): azdata.Component[] {
|
||||
if (this._postgresModel.configLastUpdated) {
|
||||
this.editWorkerNodeCount();
|
||||
this.editCores();
|
||||
this.editMemory();
|
||||
}
|
||||
|
||||
return [
|
||||
this.createWorkerNodesSectionContainer(),
|
||||
this.createCoresMemorySection(),
|
||||
this.createConfigurationSectionContainer(loc.coresRequest, this.coresRequestBox!),
|
||||
this.createConfigurationSectionContainer(loc.coresLimit, this.coresLimitBox!),
|
||||
this.createConfigurationSectionContainer(loc.memoryRequest, this.memoryRequestBox!),
|
||||
this.createConfigurationSectionContainer(loc.memoryLimit, this.memoryLimitBox!)
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
private createWorkerNodesSectionContainer(): azdata.FlexContainer {
|
||||
const inputFlex = { flex: '0 1 150px' };
|
||||
const keyFlex = { flex: `0 1 250px` };
|
||||
|
||||
const flexContainer = this.modelView.modelBuilder.flexContainer().withLayout({
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center'
|
||||
}).component();
|
||||
|
||||
const keyComponent = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.workerNodeCount,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const keyContainer = this.modelView.modelBuilder.flexContainer().withLayout({ alignItems: 'center' }).component();
|
||||
keyContainer.addItem(keyComponent, { CSSStyles: { 'margin-right': '0px', 'margin-bottom': '15px' } });
|
||||
|
||||
const information = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
iconPath: IconPathHelper.information,
|
||||
title: loc.workerNodesInformation,
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
keyContainer.addItem(information, { CSSStyles: { 'margin-left': '5px', 'margin-bottom': '15px' } });
|
||||
flexContainer.addItem(keyContainer, keyFlex);
|
||||
|
||||
const inputContainer = this.modelView.modelBuilder.flexContainer().withLayout({ alignItems: 'center' }).component();
|
||||
inputContainer.addItem(this.workerBox!, { CSSStyles: { 'margin-bottom': '15px', 'min-width': '50px', 'max-width': '225px' } });
|
||||
|
||||
flexContainer.addItem(inputContainer, inputFlex);
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private createConfigurationSectionContainer(key: string, input: azdata.Component): azdata.FlexContainer {
|
||||
const inputFlex = { flex: '0 1 150px' };
|
||||
const keyFlex = { flex: `0 1 250px` };
|
||||
|
||||
const flexContainer = this.modelView.modelBuilder.flexContainer().withLayout({
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center'
|
||||
}).component();
|
||||
|
||||
const keyComponent = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: key,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const keyContainer = this.modelView.modelBuilder.flexContainer().withLayout({ alignItems: 'center' }).component();
|
||||
keyContainer.addItem(keyComponent, { CSSStyles: { 'margin-right': '0px', 'margin-bottom': '15px' } });
|
||||
flexContainer.addItem(keyContainer, keyFlex);
|
||||
|
||||
const inputContainer = this.modelView.modelBuilder.flexContainer().withLayout({ alignItems: 'center' }).component();
|
||||
inputContainer.addItem(input, { CSSStyles: { 'margin-bottom': '15px', 'min-width': '50px', 'max-width': '225px' } });
|
||||
|
||||
flexContainer.addItem(inputContainer, inputFlex);
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private handleOnTextChanged(component: azdata.InputBoxComponent): boolean {
|
||||
if ((!component.value)) {
|
||||
// if there is no text found in the inputbox component return false
|
||||
return false;
|
||||
} else if ((!component.valid)) {
|
||||
// if value given by user is not valid enable discard button for user
|
||||
// to clear all inputs and return false
|
||||
this.discardButton!.enabled = true;
|
||||
return false;
|
||||
} else {
|
||||
// if a valid value has been entered into the input box, enable save and discard buttons
|
||||
// so that user could choose to either edit instance or clear all inputs
|
||||
// return true
|
||||
this.saveButton!.enabled = true;
|
||||
this.discardButton!.enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private editWorkerNodeCount() {
|
||||
// scale.shards was renamed to scale.workers. Check both for backwards compatibility.
|
||||
let scale = this._postgresModel.config?.spec.scale;
|
||||
let currentWorkers = scale?.workers ?? scale?.shards ?? 0;
|
||||
|
||||
this.workerBox!.min = currentWorkers;
|
||||
this.workerBox!.placeHolder = currentWorkers.toString();
|
||||
this.workerBox!.value = '';
|
||||
|
||||
this.saveArgs.workers = undefined;
|
||||
}
|
||||
|
||||
private createCoresMemorySection(): azdata.DivContainer {
|
||||
const titleFlex = { flex: `0 1 250px` };
|
||||
|
||||
const flexContainer = this.modelView.modelBuilder.flexContainer().withLayout({
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center'
|
||||
}).component();
|
||||
|
||||
const titleComponent = this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.configurationPerNode,
|
||||
CSSStyles: { ...cssStyles.title, 'font-weight': 'bold', 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const titleContainer = this.modelView.modelBuilder.flexContainer().withLayout({ alignItems: 'center' }).component();
|
||||
titleContainer.addItem(titleComponent, { CSSStyles: { 'margin-right': '0px', 'margin-bottom': '15px' } });
|
||||
|
||||
const information = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
iconPath: IconPathHelper.information,
|
||||
title: loc.configurationInformation,
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
titleContainer.addItem(information, { CSSStyles: { 'margin-left': '5px', 'margin-bottom': '15px' } });
|
||||
flexContainer.addItem(titleContainer, titleFlex);
|
||||
|
||||
let configurationSection = this.modelView.modelBuilder.divContainer().component();
|
||||
configurationSection.addItem(flexContainer);
|
||||
|
||||
return configurationSection;
|
||||
}
|
||||
|
||||
private editCores() {
|
||||
let currentCPUSize = this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.cpu;
|
||||
|
||||
if (!currentCPUSize) {
|
||||
currentCPUSize = '';
|
||||
}
|
||||
|
||||
this.coresRequestBox!.placeHolder = currentCPUSize;
|
||||
this.coresRequestBox!.value = '';
|
||||
this.saveArgs.coresRequest = undefined;
|
||||
|
||||
currentCPUSize = this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.cpu;
|
||||
|
||||
if (!currentCPUSize) {
|
||||
currentCPUSize = '';
|
||||
}
|
||||
|
||||
this.coresLimitBox!.placeHolder = currentCPUSize;
|
||||
this.coresLimitBox!.value = '';
|
||||
this.saveArgs.coresLimit = undefined;
|
||||
}
|
||||
|
||||
private editMemory() {
|
||||
let currentMemSizeConversion: string;
|
||||
let currentMemorySize = this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.memory;
|
||||
|
||||
if (!currentMemorySize) {
|
||||
currentMemSizeConversion = '';
|
||||
} else {
|
||||
currentMemSizeConversion = convertToGibibyteString(currentMemorySize);
|
||||
}
|
||||
|
||||
this.memoryRequestBox!.placeHolder = currentMemSizeConversion!;
|
||||
this.memoryRequestBox!.value = '';
|
||||
|
||||
this.saveArgs.memoryRequest = undefined;
|
||||
|
||||
currentMemorySize = this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.memory;
|
||||
|
||||
if (!currentMemorySize) {
|
||||
currentMemSizeConversion = '';
|
||||
} else {
|
||||
currentMemSizeConversion = convertToGibibyteString(currentMemorySize);
|
||||
}
|
||||
|
||||
this.memoryLimitBox!.placeHolder = currentMemSizeConversion!;
|
||||
this.memoryLimitBox!.value = '';
|
||||
|
||||
this.saveArgs.memoryLimit = undefined;
|
||||
}
|
||||
|
||||
private handleServiceUpdated() {
|
||||
this.editWorkerNodeCount();
|
||||
this.editCores();
|
||||
this.editMemory();
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ export class PostgresConnectionStringsPage extends DashboardPage {
|
||||
|
||||
const link = this.modelView.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({
|
||||
label: loc.learnAboutPostgresClients,
|
||||
url: 'https://docs.microsoft.com/azure/azure-arc/data/get-connection-endpoints-and-connection-strings-postgres-hyperscale',
|
||||
url: 'https://docs.microsoft.com/azure/postgresql/concepts-connection-libraries',
|
||||
}).component();
|
||||
|
||||
const infoAndLink = this.modelView.modelBuilder.flexContainer().withLayout({ flexWrap: 'wrap' }).component();
|
||||
@@ -82,7 +82,8 @@ export class PostgresConnectionStringsPage extends DashboardPage {
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'PHP', `host=${endpoint.ip} port=${endpoint.port} dbname=postgres user=postgres password={your_password_here} sslmode=require`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'psql', `psql "host=${endpoint.ip} port=${endpoint.port} dbname=postgres user=postgres password={your_password_here} sslmode=require"`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Python', `dbname='postgres' user='postgres' host='${endpoint.ip}' password='{your_password_here}' port='${endpoint.port}' sslmode='true'`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Ruby', `host=${endpoint.ip}; dbname=postgres user=postgres password={your_password_here} port=${endpoint.port} sslmode=require`)
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Ruby', `host=${endpoint.ip}; dbname=postgres user=postgres password={your_password_here} port=${endpoint.port} sslmode=require`),
|
||||
new InputKeyValue(this.modelView.modelBuilder, 'Web App', `Database=postgres; Data Source=${endpoint.ip}; User Id=postgres; Password={your_password_here}`)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import { PostgresConnectionStringsPage } from './postgresConnectionStringsPage';
|
||||
import { Dashboard } from '../../components/dashboard';
|
||||
import { PostgresDiagnoseAndSolveProblemsPage } from './postgresDiagnoseAndSolveProblemsPage';
|
||||
import { PostgresSupportRequestPage } from './postgresSupportRequestPage';
|
||||
import { PostgresComputeAndStoragePage } from './postgresComputeAndStoragePage';
|
||||
|
||||
export class PostgresDashboard extends Dashboard {
|
||||
constructor(private _context: vscode.ExtensionContext, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
@@ -31,7 +30,6 @@ export class PostgresDashboard extends Dashboard {
|
||||
protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> {
|
||||
const overviewPage = new PostgresOverviewPage(modelView, this._controllerModel, this._postgresModel);
|
||||
const connectionStringsPage = new PostgresConnectionStringsPage(modelView, this._postgresModel);
|
||||
const computeAndStoragePage = new PostgresComputeAndStoragePage(modelView, this._postgresModel);
|
||||
// TODO: Removed properties page while investigating bug where refreshed values don't appear in UI
|
||||
// const propertiesPage = new PostgresPropertiesPage(modelView, this._controllerModel, this._postgresModel);
|
||||
const diagnoseAndSolveProblemsPage = new PostgresDiagnoseAndSolveProblemsPage(modelView, this._context, this._postgresModel);
|
||||
@@ -42,8 +40,7 @@ export class PostgresDashboard extends Dashboard {
|
||||
{
|
||||
title: loc.settings,
|
||||
tabs: [
|
||||
connectionStringsPage.tab,
|
||||
computeAndStoragePage.tab
|
||||
connectionStringsPage.tab
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,226 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="eec7d136-f112-46af-a3cf-bf91a5c75666"
|
||||
data-name="Layer 1"
|
||||
width="59.994473"
|
||||
height="60"
|
||||
viewBox="0 0 59.994473 60"
|
||||
version="1.1"
|
||||
sodipodi:docname="sqldb_edge.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata71">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1356"
|
||||
inkscape:window-height="974"
|
||||
id="namedview69"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.36"
|
||||
inkscape:cx="29.997181"
|
||||
inkscape:cy="30"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="eec7d136-f112-46af-a3cf-bf91a5c75666" />
|
||||
<defs
|
||||
id="defs38">
|
||||
<linearGradient
|
||||
id="b5c6b104-454d-4729-acd6-907263c2d466"
|
||||
x1="57.186001"
|
||||
y1="740.06403"
|
||||
x2="70.387001"
|
||||
y2="740.06403"
|
||||
gradientTransform="matrix(1,0,0,-1,0,770)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#005ba1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="0.068"
|
||||
stop-color="#0060a9"
|
||||
id="stop4" />
|
||||
<stop
|
||||
offset="0.356"
|
||||
stop-color="#0071c8"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="0.517"
|
||||
stop-color="#0078d4"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="0.642"
|
||||
stop-color="#0074cd"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="0.82"
|
||||
stop-color="#006abb"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#005ba1"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="a7ff9d6f-dfc1-44bf-b13b-162305f1fa8a"
|
||||
x1="52.797001"
|
||||
y1="704.80798"
|
||||
x2="52.797001"
|
||||
y2="742.84399"
|
||||
gradientTransform="matrix(1,0,0,-1,0,770)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#198ab3"
|
||||
id="stop17" />
|
||||
<stop
|
||||
offset="0.097"
|
||||
stop-color="#209ec5"
|
||||
id="stop19" />
|
||||
<stop
|
||||
offset="0.242"
|
||||
stop-color="#28b6da"
|
||||
id="stop21" />
|
||||
<stop
|
||||
offset="0.396"
|
||||
stop-color="#2ec7e9"
|
||||
id="stop23" />
|
||||
<stop
|
||||
offset="0.565"
|
||||
stop-color="#31d1f2"
|
||||
id="stop25" />
|
||||
<stop
|
||||
offset="0.775"
|
||||
stop-color="#32d4f5"
|
||||
id="stop27" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="bc37103c-430d-46e7-aa83-30a9235b7b74"
|
||||
x1="36.847"
|
||||
y1="702.948"
|
||||
x2="59.476002"
|
||||
y2="702.948"
|
||||
xlink:href="#b5c6b104-454d-4729-acd6-907263c2d466" />
|
||||
<radialGradient
|
||||
id="e36b5364-8f7a-422d-a36a-9a21681809ae"
|
||||
cx="48.790001"
|
||||
cy="702.229"
|
||||
r="12.478"
|
||||
gradientTransform="matrix(1,0,0,-1,0,770)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#f2f2f2"
|
||||
id="stop31" />
|
||||
<stop
|
||||
offset="0.58"
|
||||
stop-color="#eee"
|
||||
id="stop33" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#e6e6e6"
|
||||
id="stop35" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#b5c6b104-454d-4729-acd6-907263c2d466"
|
||||
id="linearGradient4581"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,770)"
|
||||
x1="57.186001"
|
||||
y1="740.06403"
|
||||
x2="70.387001"
|
||||
y2="740.06403" />
|
||||
</defs>
|
||||
<title
|
||||
id="title40">SQL_Database_Edge_100x</title>
|
||||
<g
|
||||
id="g66"
|
||||
transform="translate(-20.002819,-20)">
|
||||
<path
|
||||
d="m 57.135,30.379 c 5.493,1.494 6.882,2.438 11.833,6.466 -0.037,-0.064 -0.078,-0.12 -0.12,-0.189 -0.23,-0.369 -0.48,-0.72 -0.731,-1.062 -0.094,-0.12 -0.186,-0.253 -0.285,-0.373 -0.223,-0.275 -0.463,-0.527 -0.7,-0.78 a 13.488,13.488 0 0 0 -1.182,-1.1 l -0.012,-0.01 a 13.364,13.364 0 0 0 -4.393,-2.346 l -0.2,-0.066 q -0.507,-0.15 -1.032,-0.26 c -0.273,-0.055 -0.552,-0.1 -0.832,-0.138 -0.215,-0.031 -0.428,-0.073 -0.645,-0.094 q -0.767,-0.068 -1.537,-0.059 z"
|
||||
style="opacity:0.4;isolation:isolate;fill:#ffffff"
|
||||
id="path42"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 63.786,24.777 c -3.642,0 -6.6,-1.069 -6.6,-2.389 V 35.1 c 0,1.308 2.9,2.371 6.506,2.388 h 0.094 c 3.643,0 6.6,-1.068 6.6,-2.388 V 22.388 c -0.009,1.32 -2.962,2.389 -6.6,2.389 z"
|
||||
id="path44"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient4581)" />
|
||||
<path
|
||||
d="m 70.377,22.388 c 0,1.32 -2.953,2.389 -6.6,2.389 -3.647,0 -6.591,-1.069 -6.591,-2.389 0,-1.32 2.954,-2.388 6.6,-2.388 3.646,0 6.6,1.069 6.6,2.388"
|
||||
id="path46"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#e8e8e8" />
|
||||
<path
|
||||
d="m 68.837,22.2 c 0,0.84 -2.263,1.519 -5.055,1.519 -2.792,0 -5.056,-0.68 -5.056,-1.519 0,-0.839 2.263,-1.518 5.06,-1.518 2.797,0 5.056,0.679 5.056,1.518"
|
||||
id="path48"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#50e6ff" />
|
||||
<path
|
||||
d="m 63.786,22.545 a 12.247,12.247 0 0 0 -4,0.576 13.658,13.658 0 0 0 8,0 12.246,12.246 0 0 0 -4,-0.576 z"
|
||||
id="path50"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#198ab3" />
|
||||
<path
|
||||
d="M 79.627,53.279 A 12.057,12.057 0 0 0 69.163,41.69 C 69.083,33.65 62.109,27.158 53.512,27.158 a 15.592,15.592 0 0 0 -14.9,10.16 C 31.441,38.41 25.967,44.19 25.967,51.16 c 0,7.75 6.764,14.032 15.108,14.032 0.449,0 0.893,-0.023 1.332,-0.058 h 24.467 a 2.434,2.434 0 0 0 0.646,-0.1 C 74.257,64.761 79.627,59.6 79.627,53.279 Z"
|
||||
id="path52"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#a7ff9d6f-dfc1-44bf-b13b-162305f1fa8a)" />
|
||||
<path
|
||||
d="m 78.463,29.993 c -1.653,-2.16 -4.49,-3.21 -8.086,-3.254 v 3.6 c 2.52,0.042 4.355,0.68 5.239,1.839 C 78.651,36.156 73.137,49.2 57.263,61.4 41.389,73.6 27.411,75.561 24.378,71.581 c -1.719,-2.254 -0.653,-7.43 3.445,-13.7 a 13.266,13.266 0 0 1 -1.571,-4.006 c -5.86,8.04 -7.976,15.626 -4.721,19.9 5.217,6.841 22.191,2.587 37.913,-9.5 C 75.166,52.188 83.679,36.833 78.463,29.993 Z"
|
||||
id="path54"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0072c6" />
|
||||
<path
|
||||
d="m 48.161,58.2 c -6.247,0 -11.314,-1.835 -11.314,-4.1 v 21.8 c 0,2.244 4.983,4.067 11.16,4.1 h 0.155 c 6.249,0 11.314,-1.834 11.314,-4.1 V 54.1 c -10e-4,2.268 -5.067,4.1 -11.315,4.1 z"
|
||||
id="path56"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#bc37103c-430d-46e7-aa83-30a9235b7b74)" />
|
||||
<path
|
||||
d="m 59.475,54.105 c 0,2.263 -5.066,4.1 -11.314,4.1 -6.248,0 -11.314,-1.835 -11.314,-4.1 0,-2.265 5.067,-4.1 11.314,-4.1 6.247,0 11.314,1.835 11.314,4.1"
|
||||
id="path58"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#e8e8e8" />
|
||||
<path
|
||||
d="m 56.834,53.773 c 0,1.441 -3.883,2.606 -8.673,2.606 -4.79,0 -8.673,-1.167 -8.673,-2.606 0,-1.439 3.884,-2.605 8.673,-2.605 4.789,0 8.673,1.167 8.673,2.605"
|
||||
id="path60"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#50e6ff" />
|
||||
<path
|
||||
d="m 48.161,54.373 a 20.975,20.975 0 0 0 -6.87,0.989 20.252,20.252 0 0 0 6.87,1.017 20.262,20.262 0 0 0 6.871,-1.017 20.981,20.981 0 0 0 -6.871,-0.989 z"
|
||||
id="path62"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#198ab3" />
|
||||
<path
|
||||
d="m 55.038,69.236 v -5.96 H 53.4 v 7.292 h 4.343 V 69.236 Z M 42.452,66.3 a 3.63,3.63 0 0 1 -0.907,-0.547 0.77,0.77 0 0 1 -0.221,-0.567 0.633,0.633 0 0 1 0.274,-0.536 1.245,1.245 0 0 1 0.748,-0.2 2.887,2.887 0 0 1 1.68,0.509 v -1.52 a 4.809,4.809 0 0 0 -1.77,-0.281 2.969,2.969 0 0 0 -1.934,0.593 1.932,1.932 0 0 0 -0.722,1.569 2.394,2.394 0 0 0 1.668,2.135 4.887,4.887 0 0 1 1.086,0.631 0.751,0.751 0 0 1 0.268,0.575 0.633,0.633 0 0 1 -0.279,0.539 1.312,1.312 0 0 1 -0.786,0.2 2.917,2.917 0 0 1 -1.927,-0.743 v 1.627 a 3.968,3.968 0 0 0 1.888,0.407 3.371,3.371 0 0 0 2.079,-0.569 1.9,1.9 0 0 0 0.753,-1.608 1.832,1.832 0 0 0 -0.433,-1.241 4.491,4.491 0 0 0 -1.465,-0.973 z m 9.153,2.8 a 4.517,4.517 0 0 0 0.145,-4.17 3.154,3.154 0 0 0 -1.236,-1.32 3.523,3.523 0 0 0 -1.8,-0.464 3.786,3.786 0 0 0 -1.913,0.48 3.276,3.276 0 0 0 -1.296,1.374 4.319,4.319 0 0 0 -0.46,2.021 4.03,4.03 0 0 0 0.424,1.854 3.222,3.222 0 0 0 1.2,1.309 3.533,3.533 0 0 0 1.752,0.514 l 1.511,1.694 h 2.135 L 49.953,70.434 A 3.119,3.119 0 0 0 51.605,69.1 Z m -1.643,-0.447 a 1.639,1.639 0 0 1 -1.347,0.618 1.617,1.617 0 0 1 -1.337,-0.638 3.136,3.136 0 0 1 0.009,-3.425 1.669,1.669 0 0 1 1.37,-0.646 1.561,1.561 0 0 1 1.32,0.645 2.864,2.864 0 0 1 0.48,1.752 2.618,2.618 0 0 1 -0.495,1.698 z"
|
||||
id="path64"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#e36b5364-8f7a-422d-a36a-9a21681809ae)" />
|
||||
</g>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="ee7a2d03-25e0-4b7b-970e-53f514516b83"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<title>Azure_SQL_Edge</title>
|
||||
<path d="M49.3,22.2c-0.7-1.7-1.9-3.1-3.5-4.1c3.9-5.8,5.6-11.5,2.9-14.8c-2.8-3.4-9.3-2.9-17.8,1.4l0,0.1C29.5,4.3,28,4,26.6,4
|
||||
c-1.2,0-2.4,0.1-3.5,0.4c-2.3,0.6-4.3,1.7-6,3.3c-0.9,0.8-1.6,1.7-2.3,2.7c-0.7-0.1-1.5-0.2-2.3-0.2c-1.7,0-3.3,0.3-4.9,1
|
||||
c-3,1.3-5.4,3.7-6.7,6.7c-1.3,3.1-1.3,6.6,0,9.7c0.5,1,1.1,2,1.8,2.9l-0.1-0.1c-3,5.4-3.5,9.6-1.3,12.3c1.4,1.6,3.5,2.4,5.6,2.2
|
||||
c2.1-0.1,4.1-0.4,6-1.1c3.2,2.8,7.4,4.2,11.6,3.9c7.5,0,13.1-3.1,13.1-7.3v-5.2h2.9c1.2,0,2.5-0.2,3.6-0.7c2.2-1,4-2.8,5-5
|
||||
C50.2,27.2,50.2,24.5,49.3,22.2L49.3,22.2z M46.3,5.2c1.5,1.8,0.4,6.1-3.4,11.6c-0.8-0.2-1.6-0.3-2.4-0.3c-0.2-1.7-0.7-3.4-1.6-5
|
||||
c-0.8-1.5-1.8-2.8-3.1-4c-0.5-0.4-1-0.8-1.6-1.2C40.2,3.8,44.8,3.3,46.3,5.2z M3.9,19.1c1-2.2,2.8-4,5-5c1.2-0.5,2.4-0.7,3.6-0.7
|
||||
c1.3,0,2.6,0.3,3.9,0.9c0.4-1,0.9-2,1.6-2.9c1.3-1.7,3.2-3,5.3-3.7C25.7,6.9,28.4,7,30.8,8c2.6,1.1,4.7,3.2,5.8,5.8
|
||||
c0.6,1.3,0.9,2.8,0.9,4.3v1.6h3.1c0.1,0,0.2,0,0.3,0c-0.9,1.2-2,2.4-3.2,3.7v-0.2h-0.1c-0.6-3.8-6-6.6-13-6.6s-12.4,2.8-13,6.6h-0.1
|
||||
V32c-0.9-0.1-1.8-0.3-2.7-0.6c-2.2-1-4-2.8-5-5C2.9,24.1,2.9,21.4,3.9,19.1L3.9,19.1z M24.7,19.6c5.7,0,10,2.2,10,4.2
|
||||
s-4.3,4.2-10,4.2s-10-2.2-10-4.2S18.9,19.6,24.7,19.6z M3.7,40.8c-1.2-1.4-0.7-4.4,1.2-8.1c0.8,0.7,1.7,1.2,2.7,1.6
|
||||
c1.3,0.5,2.6,0.8,3.9,0.9v5.3c0,0.2,0.1,0.5,0.1,0.7C7.8,42.3,4.8,42.2,3.7,40.8z M24.7,44.6c-5.7,0-10-2.2-10-4.2V28.6
|
||||
c3,1.8,6.5,2.6,10,2.5c3.5,0.1,6.9-0.8,10-2.5v11.8C34.6,42.4,30.4,44.6,24.7,44.6z M46.4,28.3c-0.6,1.5-1.8,2.7-3.3,3.3
|
||||
c-0.8,0.3-1.6,0.5-2.4,0.5h-2.9v-4.4c2.2-2.2,4.3-4.6,6.2-7.1c1.1,0.7,1.9,1.7,2.4,2.8C47,25,47,26.7,46.4,28.3L46.4,28.3z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 1.9 KiB |
10
extensions/asde-deployment/images/sqldb_edge_inverse.svg
Normal file
10
extensions/asde-deployment/images/sqldb_edge_inverse.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M49.2998 22.2C48.5998 20.5 47.3998 19.1 45.7998 18.1C49.6998 12.3 51.3998 6.60003 48.6998 3.30003C45.8998 -0.099967 39.3998 0.400033 30.8998 4.70003V4.80003C29.4998 4.30003 27.9998 4.00003 26.5998 4.00003C25.3998 4.00003 24.1998 4.10003 23.0998 4.40003C20.7998 5.00003 18.7998 6.10003 17.0998 7.70003C16.1998 8.50003 15.4998 9.40003 14.7998 10.4C14.0998 10.3 13.2998 10.2 12.4998 10.2C10.7998 10.2 9.1998 10.5 7.5998 11.2C4.5998 12.5 2.1998 14.9 0.899805 17.9C-0.400195 21 -0.400195 24.5 0.899805 27.6C1.3998 28.6 1.9998 29.6 2.6998 30.5L2.5998 30.4C-0.400195 35.8 -0.900195 40 1.2998 42.7C2.6998 44.3 4.7998 45.1 6.8998 44.9C8.9998 44.8 10.9998 44.5 12.8998 43.8C16.0998 46.6 20.2998 48 24.4998 47.7C31.9998 47.7 37.5998 44.6 37.5998 40.4V35.2H40.4998C41.6998 35.2 42.9998 35 44.0998 34.5C46.2998 33.5 48.0998 31.7 49.0998 29.5C50.1998 27.2 50.1998 24.5 49.2998 22.2ZM46.2998 5.20003C47.7998 7.00003 46.6998 11.3 42.8998 16.8C42.0998 16.6 41.2998 16.5 40.4998 16.5C40.2998 14.8 39.7998 13.1 38.8998 11.5C38.0998 10 37.0998 8.70003 35.7998 7.50003C35.2998 7.10003 34.7998 6.70003 34.1998 6.30003C40.1998 3.80003 44.7998 3.30003 46.2998 5.20003ZM3.8998 19.1C4.8998 16.9 6.6998 15.1 8.8998 14.1C10.0998 13.6 11.2998 13.4 12.4998 13.4C13.7998 13.4 15.0998 13.7 16.3998 14.3C16.7998 13.3 17.2998 12.3 17.9998 11.4C19.2998 9.70003 21.1998 8.40003 23.2998 7.70003C25.6998 6.90003 28.3998 7.00003 30.7998 8.00003C33.3998 9.10003 35.4998 11.2 36.5998 13.8C37.1998 15.1 37.4998 16.6 37.4998 18.1V19.7H40.5998C40.6998 19.7 40.7998 19.7 40.8998 19.7C39.9998 20.9 38.8998 22.1 37.6998 23.4V23.2H37.5998C36.9998 19.4 31.5998 16.6 24.5998 16.6C17.5998 16.6 12.1998 19.4 11.5998 23.2H11.4998V32C10.5998 31.9 9.6998 31.7 8.7998 31.4C6.5998 30.4 4.7998 28.6 3.7998 26.4C2.8998 24.1 2.8998 21.4 3.8998 19.1ZM24.6998 19.6C30.3998 19.6 34.6998 21.8 34.6998 23.8C34.6998 25.8 30.3998 28 24.6998 28C18.9998 28 14.6998 25.8 14.6998 23.8C14.6998 21.8 18.8998 19.6 24.6998 19.6ZM3.6998 40.8C2.4998 39.4 2.9998 36.4 4.8998 32.7C5.6998 33.4 6.5998 33.9 7.5998 34.3C8.8998 34.8 10.1998 35.1 11.4998 35.2V40.5C11.4998 40.7 11.5998 41 11.5998 41.2C7.7998 42.3 4.7998 42.2 3.6998 40.8ZM24.6998 44.6C18.9998 44.6 14.6998 42.4 14.6998 40.4V28.6C17.6998 30.4 21.1998 31.2 24.6998 31.1C28.1998 31.2 31.5998 30.3 34.6998 28.6V40.4C34.5998 42.4 30.3998 44.6 24.6998 44.6ZM46.3998 28.3C45.7998 29.8 44.5998 31 43.0998 31.6C42.2998 31.9 41.4998 32.1 40.6998 32.1H37.7998V27.7C39.9998 25.5 42.0998 23.1 43.9998 20.6C45.0998 21.3 45.8998 22.3 46.3998 23.4C46.9998 25 46.9998 26.7 46.3998 28.3Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="50" height="50" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -29,7 +29,7 @@
|
||||
"1. Create an Azure Edge VM as a virtual IoT device, you can go the \"Default Settings\" cell and adjust the vm_size variable based on your needs. Available sizes and pricing information can be found [here](https://docs.microsoft.com/azure/virtual-machines/linux/sizes).\n",
|
||||
"1. Create an Azure IoT hub, you can go to the \"Default Settings\" cell and adjust value of the following variables based on your needs: iot_hub_sku and iot_hub_units. Available SKUs and pricing information can be found [here](https://azure.microsoft.com/pricing/details/iot-hub/).\n",
|
||||
"1. Add the device to the IoT hub\n",
|
||||
"1. Deploy SQL Edge module to the device with optional package file\n",
|
||||
"1. Deploy SQL Edge module to the device with optional dacpac\n",
|
||||
"1. Enable connecting to the SQL Edge instance on the device\n",
|
||||
"\n",
|
||||
"### Dependencies\n",
|
||||
@@ -97,11 +97,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"extensions = run_command('az extension list', returnObject=True)\r\n",
|
||||
"extensions = [ext for ext in extensions if ext['name'] == 'azure-cli-iot-ext']\r\n",
|
||||
"if len(extensions) > 0:\r\n",
|
||||
" run_command('az extension remove --name azure-cli-iot-ext')\r\n",
|
||||
"run_command('az extension add --name azure-iot')"
|
||||
"run_command('az extension add --name azure-cli-iot-ext')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "55bb2f96-6f7f-4aa0-9daf-d0f7f9d9243c",
|
||||
@@ -130,7 +126,7 @@
|
||||
"sa_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n",
|
||||
"vm_admin = os.environ[\"AZDATA_NB_VAR_ASDE_VM_ADMIN\"]\n",
|
||||
"vm_password = os.environ[\"AZDATA_NB_VAR_ASDE_VM_PASSWORD\"]\n",
|
||||
"package_path = os.environ[\"AZDATA_NB_VAR_ASDE_PACKAGE_PATH\"]\n",
|
||||
"dacpac_path = os.environ[\"AZDATA_NB_VAR_ASDE_DACPAC_PATH\"]\n",
|
||||
"sql_port = os.environ[\"AZDATA_NB_VAR_ASDE_SQL_PORT\"]\n",
|
||||
"new_rg_flag = os.environ[\"AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP\"]\n",
|
||||
"new_rg_name = os.environ[\"AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP_NAME\"]\n",
|
||||
@@ -144,7 +140,7 @@
|
||||
"print(f'VM admin password: ******')\n",
|
||||
"print(f'SQL Server port: {sql_port}')\n",
|
||||
"print(f'SQL Server sa password: ******')\n",
|
||||
"print(f'Package path: {package_path}')"
|
||||
"print(f'Dacpac path: {dacpac_path}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "dde9388b-f623-4d62-bb74-36a05f5d2ea3",
|
||||
@@ -180,7 +176,7 @@
|
||||
"subnet_address_prefix = '10.0.0.0/24'\n",
|
||||
"vnet_address_prefix = '10.0.0.0/16'\n",
|
||||
"azure_storage_account = f'sa{suffix}'\n",
|
||||
"storage_account_container = 'sqldatabasepackage'\n",
|
||||
"storage_account_container = 'sqldatabasedacpac'\n",
|
||||
"sql_lcid = '1033'\n",
|
||||
"sql_collation = 'SQL_Latin1_General_CP1_CI_AS'"
|
||||
],
|
||||
@@ -274,7 +270,7 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create storage account and storage account container, then upload the package"
|
||||
"### Create storage account and storage account container, then upload the dacpac"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "90ec2b26-0c4a-4aa4-b397-f16b09b454ea"
|
||||
@@ -284,11 +280,11 @@
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"storage_account_created = False\n",
|
||||
"if package_path == \"\":\n",
|
||||
" print(f'Package file not provided')\n",
|
||||
"if dacpac_path == \"\":\n",
|
||||
" print(f'Dacpac zip file not provided')\n",
|
||||
" blob_sas = ''\n",
|
||||
"else: \n",
|
||||
" package_name = ntpath.basename(package_path)\n",
|
||||
" dacpac_name = ntpath.basename(dacpac_path)\n",
|
||||
" storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)\n",
|
||||
" storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]\n",
|
||||
" if len(storage_accounts) == 0:\n",
|
||||
@@ -304,14 +300,14 @@
|
||||
" else:\n",
|
||||
" run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')\n",
|
||||
"\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{package_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" if blob_exists:\n",
|
||||
" print(f'blob \\\"{package_name}\\\" already exists.')\n",
|
||||
" print(f'blob \\\"{dacpac_name}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {package_name} --file \\\"{package_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {dacpac_name} --file \\\"{dacpac_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" now = time.localtime()\n",
|
||||
" expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'\n",
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{package_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "7ab2b3ec-0832-40b3-98c0-4aa87320e7ce",
|
||||
@@ -479,9 +475,8 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"PlanId=asde-developer-on-iot-edge\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}<PACKAGE_INFO>},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_SAS_URL>\\\"}}}}'\n",
|
||||
"package_info = '' if blob_sas == ''else ',\\\"MSSQL_PACKAGE\\\":{\\\"value\\\":\\\"'+blob_sas+'\\\"}'\n",
|
||||
"manifest = manifest.replace('<PACKAGE_INFO>', package_info).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge-developer\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"MSSQL_PID=Developer\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"SqlPackage\\\":\\\"<Optional_DACPAC_ZIP_SAS_URL>\\\",\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_ZIP_SAS_URL>\\\"}}}}'\n",
|
||||
"manifest = manifest.replace('<Optional_DACPAC_ZIP_SAS_URL>', blob_sas).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"file_name = f'{uuid.uuid4().hex}.json'\n",
|
||||
"manifest_file = open(file_name, 'w')\n",
|
||||
"manifest_file.write(manifest)\n",
|
||||
@@ -530,7 +525,7 @@
|
||||
"source": [
|
||||
"if storage_account_created:\r\n",
|
||||
" delete_storage_account_command = \"run_command(f'az storage account delete -n {azure_storage_account} -g {azure_resource_group} --yes')\"\r\n",
|
||||
" display(HTML('<span style=\"color:red\"><font size=\"2\">NOTE: A storage account was created to host the package file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))\r\n",
|
||||
" display(HTML('<span style=\"color:red\"><font size=\"2\">NOTE: A storage account was created to host the dacpac file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))\r\n",
|
||||
" display(HTML('<span><font size=\"2\">'+delete_storage_account_command+'</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"template = Template(f'docker run -e ACCEPT_EULA=Y -e \"SA_PASSWORD=$password\" -e \"MSSQL_PID=Developer\" -p {sql_port}:1433 --name {container_name} -d {docker_registry}/{docker_repository}:{docker_imagetag}')\n",
|
||||
"template = Template(f'docker run -e ACCEPT_EULA=Y -e \"SA_PASSWORD=$password\" -p {sql_port}:1433 --name {container_name} -d {docker_registry}/{docker_repository}:{docker_imagetag}')\n",
|
||||
"cmd = template.substitute(password=sql_password)\n",
|
||||
"run_command(template.substitute(password='******'))"
|
||||
],
|
||||
|
||||
@@ -92,15 +92,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"extensions = run_command('az extension list', returnObject=True)\r\n",
|
||||
"extensions = [ext for ext in extensions if ext['name'] == 'azure-cli-iot-ext']\r\n",
|
||||
"if len(extensions) > 0:\r\n",
|
||||
" run_command('az extension remove --name azure-cli-iot-ext')\r\n",
|
||||
"run_command('az extension add --name azure-iot')"
|
||||
"run_command('az extension add --name azure-cli-iot-ext')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "55bb2f96-6f7f-4aa0-9daf-d0f7f9d9243c",
|
||||
"tags": []
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
@@ -120,7 +118,7 @@
|
||||
"azure_subscription_id = os.environ[\"AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID\"]\n",
|
||||
"azure_resource_group = os.environ[\"AZDATA_NB_VAR_ASDE_RESOURCEGROUP\"]\n",
|
||||
"sa_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n",
|
||||
"package_path = os.environ[\"AZDATA_NB_VAR_ASDE_PACKAGE_PATH\"]\n",
|
||||
"dacpac_path = os.environ[\"AZDATA_NB_VAR_ASDE_DACPAC_PATH\"]\n",
|
||||
"sql_port = os.environ[\"AZDATA_NB_VAR_ASDE_SQL_PORT\"]\n",
|
||||
"iot_hub_name = os.environ[\"AZDATA_NB_VAR_ASDE_HUBNAME\"]\n",
|
||||
"target_condition = os.environ[\"AZDATA_NB_VAR_ASDE_TARGET_CONDITION\"]\n",
|
||||
@@ -130,7 +128,7 @@
|
||||
"print(f'Target condition: {target_condition}')\n",
|
||||
"print(f'Azure SQL Edge instance port: {sql_port}')\n",
|
||||
"print(f'Azure SQL Edge instance sa password: ******')\n",
|
||||
"print(f'Package path: {package_path}')"
|
||||
"print(f'Dacpac path: {dacpac_path}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "dde9388b-f623-4d62-bb74-36a05f5d2ea3",
|
||||
@@ -156,7 +154,7 @@
|
||||
"suffix = time.strftime(\"%y%m%d%H%M%S\", time.localtime())\n",
|
||||
"azure_storage_account = f'sa{suffix}'\n",
|
||||
"deployment_id = f'asde{suffix}'\n",
|
||||
"storage_account_container = 'sqldatabasepackage'\n",
|
||||
"storage_account_container = 'sqldatabasedacpac'\n",
|
||||
"sql_lcid = '1033'\n",
|
||||
"sql_collation = 'SQL_Latin1_General_CP1_CI_AS'\n",
|
||||
"deployment_priority = 10"
|
||||
@@ -249,7 +247,7 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create storage account and storage account container, then upload the package"
|
||||
"### Create storage account and storage account container, then upload the dacpac"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "90ec2b26-0c4a-4aa4-b397-f16b09b454ea"
|
||||
@@ -259,11 +257,11 @@
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"storage_account_created = False\n",
|
||||
"if package_path == \"\":\n",
|
||||
" print(f'Package file not provided')\n",
|
||||
"if dacpac_path == \"\":\n",
|
||||
" print(f'Dacpac zip file not provided')\n",
|
||||
" blob_sas = ''\n",
|
||||
"else:\n",
|
||||
" package_name = ntpath.basename(package_path)\n",
|
||||
" dacpac_name = ntpath.basename(dacpac_path)\n",
|
||||
" storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)\n",
|
||||
" storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]\n",
|
||||
" if len(storage_accounts) == 0:\n",
|
||||
@@ -279,14 +277,14 @@
|
||||
" else:\n",
|
||||
" run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')\n",
|
||||
"\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{package_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" if blob_exists:\n",
|
||||
" print(f'blob \\\"{package_name}\\\" already exists.')\n",
|
||||
" print(f'blob \\\"{dacpac_name}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {package_name} --file \\\"{package_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {dacpac_name} --file \\\"{dacpac_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" now = time.localtime()\n",
|
||||
" expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'\n",
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{package_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "7ab2b3ec-0832-40b3-98c0-4aa87320e7ce",
|
||||
@@ -309,9 +307,8 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"PlanId=asde-developer-on-iot-edge\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}<PACKAGE_INFO>},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_SAS_URL>\\\"}}}}'\n",
|
||||
"package_info = '' if blob_sas == ''else ',\\\"MSSQL_PACKAGE\\\":{\\\"value\\\":\\\"'+blob_sas+'\\\"}'\n",
|
||||
"manifest = manifest.replace('<PACKAGE_INFO>', package_info).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge-developer\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"MSSQL_PID=Developer\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"SqlPackage\\\":\\\"<Optional_DACPAC_ZIP_SAS_URL>\\\",\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_ZIP_SAS_URL>\\\"}}}}'\n",
|
||||
"manifest = manifest.replace('<Optional_DACPAC_ZIP_SAS_URL>', blob_sas).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"file_name = f'{uuid.uuid4().hex}.json'\n",
|
||||
"manifest_file = open(file_name, 'w')\n",
|
||||
"manifest_file.write(manifest)\n",
|
||||
@@ -334,7 +331,7 @@
|
||||
"from IPython.display import *\r\n",
|
||||
"if storage_account_created:\r\n",
|
||||
" delete_storage_account_command = \"run_command(f'az storage account delete -n {azure_storage_account} -g {azure_resource_group} --yes')\"\r\n",
|
||||
" display(HTML('<span style=\"color:red\"><font size=\"2\">NOTE: A storage account was created to host the package file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))\r\n",
|
||||
" display(HTML('<span style=\"color:red\"><font size=\"2\">NOTE: A storage account was created to host the dacpac file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))\r\n",
|
||||
" display(HTML('<span><font size=\"2\">'+delete_storage_account_command+'</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"cmd = f'docker run -e ACCEPT_EULA=Y -e \"SA_PASSWORD={sql_password}\" -e \"MSSQL_PID=Developer\" -p {sql_port}:1433 --name {container_name} -d {docker_registry}/{docker_repository}:{docker_imagetag}'\n",
|
||||
"cmd = f'docker run -e ACCEPT_EULA=Y -e \"SA_PASSWORD={sql_password}\" -p {sql_port}:1433 --name {container_name} -d {docker_registry}/{docker_repository}:{docker_imagetag}'\n",
|
||||
"run_command_remote()"
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
"\n",
|
||||
"## Deploy Azure SQL Edge to an existing device via IoT hub\n",
|
||||
"This notebook will walk you through process of deploying Azure SQL Edge to an existing device of an IoT hub:\n",
|
||||
"1. Deploy Azure SQL Edge module to the device with optional package\n",
|
||||
"1. If a package is selected, a storage account will be created to host the package file\n",
|
||||
"1. Deploy Azure SQL Edge module to the device with optional dacpac\n",
|
||||
"1. If a dacpac is selected, a storage account will be created to host the dacpac file\n",
|
||||
"1. Enable connecting to the Azure SQL Edge instance on the device\n",
|
||||
"\n",
|
||||
"### Dependencies\n",
|
||||
@@ -95,11 +95,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"extensions = run_command('az extension list', returnObject=True)\r\n",
|
||||
"extensions = [ext for ext in extensions if ext['name'] == 'azure-cli-iot-ext']\r\n",
|
||||
"if len(extensions) > 0:\r\n",
|
||||
" run_command('az extension remove --name azure-cli-iot-ext')\r\n",
|
||||
"run_command('az extension add --name azure-iot')"
|
||||
"run_command('az extension add --name azure-cli-iot-ext')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "55bb2f96-6f7f-4aa0-9daf-d0f7f9d9243c",
|
||||
@@ -125,7 +121,7 @@
|
||||
"azure_subscription_id = os.environ[\"AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID\"]\n",
|
||||
"azure_resource_group = os.environ[\"AZDATA_NB_VAR_ASDE_RESOURCEGROUP\"]\n",
|
||||
"sa_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n",
|
||||
"package_path = os.environ[\"AZDATA_NB_VAR_ASDE_PACKAGE_PATH\"]\n",
|
||||
"dacpac_path = os.environ[\"AZDATA_NB_VAR_ASDE_DACPAC_PATH\"]\n",
|
||||
"sql_port = os.environ[\"AZDATA_NB_VAR_ASDE_SQL_PORT\"]\n",
|
||||
"iot_hub_name = os.environ[\"AZDATA_NB_VAR_ASDE_HUBNAME\"]\n",
|
||||
"iot_device_id = os.environ[\"AZDATA_NB_VAR_ASDE_DEVICE_ID\"]\n",
|
||||
@@ -137,7 +133,7 @@
|
||||
"print(f'Device IP address: {ip_address}')\n",
|
||||
"print(f'Azure SQL Edge instance port: {sql_port}')\n",
|
||||
"print(f'Azure SQL Edge instance sa password: ******')\n",
|
||||
"print(f'Package path: {package_path}')"
|
||||
"print(f'Dacpac path: {dacpac_path}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "dde9388b-f623-4d62-bb74-36a05f5d2ea3",
|
||||
@@ -162,13 +158,15 @@
|
||||
"source": [
|
||||
"suffix = time.strftime(\"%y%m%d%H%M%S\", time.localtime())\n",
|
||||
"azure_storage_account = f'sa{suffix}'\n",
|
||||
"storage_account_container = 'sqldatabasepackage'\n",
|
||||
"storage_account_container = 'sqldatabasedacpac'\n",
|
||||
"sql_lcid = '1033'\n",
|
||||
"sql_collation = 'SQL_Latin1_General_CP1_CI_AS'"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "19ebeaf4-94c9-4d2b-bd9f-e3c6bf7f2dda",
|
||||
"tags": []
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
@@ -257,7 +255,7 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create storage account and storage account container, then upload the package"
|
||||
"### Create storage account and storage account container, then upload the dacpac"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "90ec2b26-0c4a-4aa4-b397-f16b09b454ea"
|
||||
@@ -267,11 +265,11 @@
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"storage_account_created = False\n",
|
||||
"if package_path == \"\":\n",
|
||||
" print(f'Package file not provided')\n",
|
||||
"if dacpac_path == \"\":\n",
|
||||
" print(f'Dacpac zip file not provided')\n",
|
||||
" blob_sas = ''\n",
|
||||
"else:\n",
|
||||
" package_name = ntpath.basename(package_path)\n",
|
||||
" dacpac_name = ntpath.basename(dacpac_path)\n",
|
||||
" storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)\n",
|
||||
" storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]\n",
|
||||
" if len(storage_accounts) == 0:\n",
|
||||
@@ -287,14 +285,14 @@
|
||||
" else:\n",
|
||||
" run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')\n",
|
||||
"\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{package_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" if blob_exists:\n",
|
||||
" print(f'blob \\\"{package_name}\\\" already exists.')\n",
|
||||
" print(f'blob \\\"{dacpac_name}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {package_name} --file \\\"{package_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {dacpac_name} --file \\\"{dacpac_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" now = time.localtime()\n",
|
||||
" expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'\n",
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{package_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "7ab2b3ec-0832-40b3-98c0-4aa87320e7ce",
|
||||
@@ -317,9 +315,8 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"PlanId=asde-developer-on-iot-edge\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}<PACKAGE_INFO>},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_SAS_URL>\\\"}}}}'\n",
|
||||
"package_info = '' if blob_sas == ''else ',\\\"MSSQL_PACKAGE\\\":{\\\"value\\\":\\\"'+blob_sas+'\\\"}'\n",
|
||||
"manifest = manifest.replace('<PACKAGE_INFO>', package_info).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge-developer\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"MSSQL_PID=Developer\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"SqlPackage\\\":\\\"<Optional_DACPAC_ZIP_SAS_URL>\\\",\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_ZIP_SAS_URL>\\\"}}}}'\n",
|
||||
"manifest = manifest.replace('<Optional_DACPAC_ZIP_SAS_URL>', blob_sas).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"file_name = f'{uuid.uuid4().hex}.json'\n",
|
||||
"manifest_file = open(file_name, 'w')\n",
|
||||
"manifest_file.write(manifest)\n",
|
||||
@@ -371,7 +368,7 @@
|
||||
"source": [
|
||||
"if storage_account_created:\r\n",
|
||||
" delete_storage_account_command = \"run_command(f'az storage account delete -n {azure_storage_account} -g {azure_resource_group} --yes')\"\r\n",
|
||||
" display(HTML('<span style=\"color:red\"><font size=\"2\">NOTE: A storage account was created to host the package file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))\r\n",
|
||||
" display(HTML('<span style=\"color:red\"><font size=\"2\">NOTE: A storage account was created to host the dacpac file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))\r\n",
|
||||
" display(HTML('<span><font size=\"2\">'+delete_storage_account_command+'</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "asde-deployment",
|
||||
"displayName": "%extension-displayName%",
|
||||
"description": "%extension-description%",
|
||||
"version": "0.4.0",
|
||||
"version": "0.1.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||
@@ -24,11 +24,11 @@
|
||||
"displayName": "%resource-type-sql-edge-display-name%",
|
||||
"description": "%resource-type-sql-edge-description%",
|
||||
"platforms": "*",
|
||||
"icon": "./images/sqldb_edge.svg",
|
||||
"tags": [
|
||||
"Hybrid",
|
||||
"SQL Server"
|
||||
],
|
||||
"icon": {
|
||||
"light": "./images/sqldb_edge.svg",
|
||||
"dark": "./images/sqldb_edge_inverse.svg"
|
||||
},
|
||||
"tags": ["Hybrid", "SQL Server"],
|
||||
"options": [
|
||||
{
|
||||
"name": "type",
|
||||
@@ -114,7 +114,7 @@
|
||||
"label": "%docker-repository-field%",
|
||||
"variableName": "AZDATA_NB_VAR_DOCKER_REPOSITORY",
|
||||
"type": "text",
|
||||
"defaultValue": "azure-sql-edge",
|
||||
"defaultValue": "azure-sql-edge-developer",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
@@ -235,7 +235,7 @@
|
||||
"label": "%docker-repository-field%",
|
||||
"variableName": "AZDATA_NB_VAR_DOCKER_REPOSITORY",
|
||||
"type": "text",
|
||||
"defaultValue": "azure-sql-edge",
|
||||
"defaultValue": "azure-sql-edge-developer",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
@@ -338,10 +338,7 @@
|
||||
"type": "password",
|
||||
"confirmationRequired": true,
|
||||
"confirmationLabel": "%vm_password_confirm%",
|
||||
"required": true,
|
||||
"textValidationRequired": true,
|
||||
"textValidationRegex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[\\W_])[A-Za-z\\d\\W_]{12,123}$",
|
||||
"textValidationDescription": "%vm_password_validation_error_message%"
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -367,17 +364,14 @@
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%package_path%",
|
||||
"description": "%package_path_description%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_PACKAGE_PATH",
|
||||
"label": "%dacpac_path%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DACPAC_PATH",
|
||||
"type": "file_picker",
|
||||
"required": false,
|
||||
"filter": {
|
||||
"displayName": "%package-files%",
|
||||
"displayName": "%dacpac-zip-files%",
|
||||
"fileTypes": [
|
||||
"zip",
|
||||
"bacpac",
|
||||
"dacpac"
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -390,7 +384,7 @@
|
||||
"requiredTools": [
|
||||
{
|
||||
"name": "azure-cli",
|
||||
"version": "2.13.0"
|
||||
"version": "2.9.1"
|
||||
}
|
||||
],
|
||||
"when": "type=azure-create-new"
|
||||
@@ -457,17 +451,14 @@
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%package_path%",
|
||||
"description": "%package_path_description%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_PACKAGE_PATH",
|
||||
"label": "%dacpac_path%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DACPAC_PATH",
|
||||
"type": "file_picker",
|
||||
"required": false,
|
||||
"filter": {
|
||||
"displayName": "%package-files%",
|
||||
"displayName": "%dacpac-zip-files%",
|
||||
"fileTypes": [
|
||||
"zip",
|
||||
"bacpac",
|
||||
"dacpac"
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -480,7 +471,7 @@
|
||||
"requiredTools": [
|
||||
{
|
||||
"name": "azure-cli",
|
||||
"version": "2.13.0"
|
||||
"version": "2.9.1"
|
||||
}
|
||||
],
|
||||
"when": "type=azure-single-device"
|
||||
@@ -550,17 +541,14 @@
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%package_path%",
|
||||
"description": "%package_path_description%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_PACKAGE_PATH",
|
||||
"label": "%dacpac_path%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DACPAC_PATH",
|
||||
"type": "file_picker",
|
||||
"required": false,
|
||||
"filter": {
|
||||
"displayName": "%package-files%",
|
||||
"displayName": "%dacpac-zip-files%",
|
||||
"fileTypes": [
|
||||
"zip",
|
||||
"bacpac",
|
||||
"dacpac"
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -573,7 +561,7 @@
|
||||
"requiredTools": [
|
||||
{
|
||||
"name": "azure-cli",
|
||||
"version": "2.13.0"
|
||||
"version": "2.9.1"
|
||||
}
|
||||
],
|
||||
"when": "type=azure-multi-device"
|
||||
@@ -594,10 +582,5 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"__metadata": {
|
||||
"id": "76",
|
||||
"publisherDisplayName": "Microsoft",
|
||||
"publisherId": "Microsoft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,10 @@
|
||||
"vm_admin": "VM admin username",
|
||||
"vm_password": "VM admin password",
|
||||
"vm_password_confirm": "Confirm VM admin password",
|
||||
"vm_password_validation_error_message": "VM password must be 12 to 123 characters in length and consists of upper case characters, lower case characters, numbers and special characters.",
|
||||
"package_path": "Package file",
|
||||
"package_path_description": "Path of the SQL Server package file(dacpac, bacpac) or compressed package file.",
|
||||
"dacpac_path": "Dacpac zip file",
|
||||
"azure-info-section-title": "Azure information",
|
||||
"sqlserver-info-section-title": "Azure SQL Edge information",
|
||||
"package-files": "SQL Server Package files",
|
||||
"dacpac-zip-files": "Dacpac zip files",
|
||||
"sql-edge-azure-single-device-display-name": "Existing device of an Azure IoT Hub",
|
||||
"sql-edge-azure-single-device-title": "Deploy Azure SQL Edge to an existing device",
|
||||
"iot-hub-name": "IoT Hub name",
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
"name": "azdata",
|
||||
"displayName": "%azdata.displayName%",
|
||||
"description": "%azdata.description%",
|
||||
"version": "0.4.1",
|
||||
"version": "0.3.1",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||
"icon": "images/extension.png",
|
||||
"engines": {
|
||||
"vscode": "*",
|
||||
"azdata": ">=1.23.0"
|
||||
"azdata": ">=1.22.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
|
||||
@@ -17,7 +17,7 @@ import { getErrorMessage, NoAzdataError, searchForCmd } from './common/utils';
|
||||
import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataInstallKey, azdataUpdateKey, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants';
|
||||
import * as loc from './localizedConstants';
|
||||
|
||||
export const enum AzdataDeployOption {
|
||||
const enum AzdataDeployOption {
|
||||
dontPrompt = 'dontPrompt',
|
||||
prompt = 'prompt'
|
||||
}
|
||||
@@ -62,7 +62,7 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
||||
|
||||
public arc = {
|
||||
dc: {
|
||||
create: (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string): Promise<azdataExt.AzdataOutput<void>> => {
|
||||
create: async (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string): Promise<azdataExt.AzdataOutput<void>> => {
|
||||
const args = ['arc', 'dc', 'create',
|
||||
'--namespace', namespace,
|
||||
'--name', name,
|
||||
@@ -79,31 +79,31 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
||||
return this.executeCommand<void>(args);
|
||||
},
|
||||
endpoint: {
|
||||
list: (): Promise<azdataExt.AzdataOutput<azdataExt.DcEndpointListResult[]>> => {
|
||||
list: async () => {
|
||||
return this.executeCommand<azdataExt.DcEndpointListResult[]>(['arc', 'dc', 'endpoint', 'list']);
|
||||
}
|
||||
},
|
||||
config: {
|
||||
list: (): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigListResult[]>> => {
|
||||
list: async () => {
|
||||
return this.executeCommand<azdataExt.DcConfigListResult[]>(['arc', 'dc', 'config', 'list']);
|
||||
},
|
||||
show: (): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigShowResult>> => {
|
||||
show: async () => {
|
||||
return this.executeCommand<azdataExt.DcConfigShowResult>(['arc', 'dc', 'config', 'show']);
|
||||
}
|
||||
}
|
||||
},
|
||||
postgres: {
|
||||
server: {
|
||||
delete: (name: string): Promise<azdataExt.AzdataOutput<void>> => {
|
||||
return this.executeCommand<void>(['arc', 'postgres', 'server', 'delete', '-n', name, '--force']);
|
||||
delete: async (name: string) => {
|
||||
return this.executeCommand<void>(['arc', 'postgres', 'server', 'delete', '-n', name]);
|
||||
},
|
||||
list: (): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerListResult[]>> => {
|
||||
list: async () => {
|
||||
return this.executeCommand<azdataExt.PostgresServerListResult[]>(['arc', 'postgres', 'server', 'list']);
|
||||
},
|
||||
show: (name: string): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerShowResult>> => {
|
||||
show: async (name: string) => {
|
||||
return this.executeCommand<azdataExt.PostgresServerShowResult>(['arc', 'postgres', 'server', 'show', '-n', name]);
|
||||
},
|
||||
edit: (
|
||||
edit: async (
|
||||
name: string,
|
||||
args: {
|
||||
adminPassword?: boolean,
|
||||
@@ -118,7 +118,7 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
||||
replaceEngineSettings?: boolean,
|
||||
workers?: number
|
||||
},
|
||||
additionalEnvVars?: { [key: string]: string }): Promise<azdataExt.AzdataOutput<void>> => {
|
||||
additionalEnvVars?: { [key: string]: string }) => {
|
||||
const argsArray = ['arc', 'postgres', 'server', 'edit', '-n', name];
|
||||
if (args.adminPassword) { argsArray.push('--admin-password'); }
|
||||
if (args.coresLimit !== undefined) { argsArray.push('--cores-limit', args.coresLimit); }
|
||||
@@ -137,20 +137,20 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
||||
},
|
||||
sql: {
|
||||
mi: {
|
||||
delete: (name: string): Promise<azdataExt.AzdataOutput<void>> => {
|
||||
delete: async (name: string) => {
|
||||
return this.executeCommand<void>(['arc', 'sql', 'mi', 'delete', '-n', name]);
|
||||
},
|
||||
list: (): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiListResult[]>> => {
|
||||
list: async () => {
|
||||
return this.executeCommand<azdataExt.SqlMiListResult[]>(['arc', 'sql', 'mi', 'list']);
|
||||
},
|
||||
show: (name: string): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiShowResult>> => {
|
||||
show: async (name: string) => {
|
||||
return this.executeCommand<azdataExt.SqlMiShowResult>(['arc', 'sql', 'mi', 'show', '-n', name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public login(endpoint: string, username: string, password: string): Promise<azdataExt.AzdataOutput<void>> {
|
||||
public async login(endpoint: string, username: string, password: string): Promise<azdataExt.AzdataOutput<void>> {
|
||||
return this.executeCommand<void>(['login', '-e', endpoint, '-u', username], { 'AZDATA_PASSWORD': password });
|
||||
}
|
||||
|
||||
@@ -239,60 +239,52 @@ export async function findAzdata(): Promise<IAzdataTool> {
|
||||
* runs the commands to install azdata, downloading the installation package if needed
|
||||
*/
|
||||
export async function installAzdata(): Promise<void> {
|
||||
const statusDisposable = vscode.window.setStatusBarMessage(loc.installingAzdata);
|
||||
Logger.show();
|
||||
Logger.log(loc.installingAzdata);
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.installingAzdata,
|
||||
cancellable: false
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await downloadAndInstallAzdataWin32();
|
||||
break;
|
||||
case 'darwin':
|
||||
await installAzdataDarwin();
|
||||
break;
|
||||
case 'linux':
|
||||
await installAzdataLinux();
|
||||
break;
|
||||
default:
|
||||
throw new Error(loc.platformUnsupported(process.platform));
|
||||
}
|
||||
try {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await downloadAndInstallAzdataWin32();
|
||||
break;
|
||||
case 'darwin':
|
||||
await installAzdataDarwin();
|
||||
break;
|
||||
case 'linux':
|
||||
await installAzdataLinux();
|
||||
break;
|
||||
default:
|
||||
throw new Error(loc.platformUnsupported(process.platform));
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
statusDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the azdata using os appropriate method
|
||||
*/
|
||||
export async function updateAzdata(): Promise<void> {
|
||||
const statusDisposable = vscode.window.setStatusBarMessage(loc.updatingAzdata);
|
||||
Logger.show();
|
||||
Logger.log(loc.updatingAzdata);
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.updatingAzdata,
|
||||
cancellable: false
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await downloadAndInstallAzdataWin32();
|
||||
break;
|
||||
case 'darwin':
|
||||
await updateAzdataDarwin();
|
||||
break;
|
||||
case 'linux':
|
||||
await installAzdataLinux();
|
||||
break;
|
||||
default:
|
||||
throw new Error(loc.platformUnsupported(process.platform));
|
||||
}
|
||||
try {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await downloadAndInstallAzdataWin32();
|
||||
break;
|
||||
case 'darwin':
|
||||
await updateAzdataDarwin();
|
||||
break;
|
||||
case 'linux':
|
||||
await installAzdataLinux();
|
||||
break;
|
||||
default:
|
||||
throw new Error(loc.platformUnsupported(process.platform));
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
statusDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@ interface PlatformReleaseInfo {
|
||||
link?: string; // "https://aka.ms/azdata-msi"
|
||||
}
|
||||
|
||||
export interface AzdataReleaseInfo {
|
||||
interface AzdataReleaseInfo {
|
||||
win32: PlatformReleaseInfo,
|
||||
darwin: PlatformReleaseInfo,
|
||||
linux: PlatformReleaseInfo
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as cp from 'child_process';
|
||||
import * as sudo from 'sudo-prompt';
|
||||
import * as loc from '../localizedConstants';
|
||||
@@ -86,7 +87,7 @@ export async function executeCommand(command: string, args: string[], additional
|
||||
export async function executeSudoCommand(command: string): Promise<ProcessOutput> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Logger.log(loc.executingCommand(`sudo ${command}`, []));
|
||||
sudo.exec(command, { name: 'Azure Data Studio' }, (error, stdout, stderr) => {
|
||||
sudo.exec(command, { name: vscode.env.appName }, (error, stdout, stderr) => {
|
||||
stdout = stdout?.toString() ?? '';
|
||||
stderr = stderr?.toString() ?? '';
|
||||
if (stdout) {
|
||||
|
||||
@@ -13,8 +13,7 @@ export class ArcControllerConfigProfilesOptionsSource implements rd.IOptionsSour
|
||||
readonly optionsSourceId = 'arc.controller.config.profiles';
|
||||
constructor(private _azdataExtApi: azdataExt.IExtension) { }
|
||||
async getOptions(): Promise<string[]> {
|
||||
const isEulaAccepted = await this._azdataExtApi.isEulaAccepted();
|
||||
if (!isEulaAccepted) { // if eula has not yet be accepted then give user a chance to accept it
|
||||
if (!this._azdataExtApi.isEulaAccepted()) { // if eula has not yet be accepted then give user a chance to accept it
|
||||
await this._azdataExtApi.promptForEula();
|
||||
}
|
||||
return (await this._azdataExtApi.azdata.arc.dc.config.list()).result;
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as sinon from 'sinon';
|
||||
import * as vscode from 'vscode';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { getExtensionApi } from '../api';
|
||||
import { AzdataToolService } from '../services/azdataToolService';
|
||||
import { assertRejected } from './testUtils';
|
||||
|
||||
describe('api', function (): void {
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
describe('getExtensionApi', function (): void {
|
||||
it('throws when no azdata', async function(): Promise<void> {
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const azdataToolService = new AzdataToolService();
|
||||
const api = getExtensionApi(mementoMock.object, azdataToolService, Promise.resolve(undefined));
|
||||
await assertRejected(api.isEulaAccepted(), 'isEulaAccepted');
|
||||
|
||||
await assertRejected(api.azdata.getPath(), 'getPath');
|
||||
await assertRejected(api.azdata.getSemVersion(), 'getSemVersion');
|
||||
await assertRejected(api.azdata.login('', '', ''), 'login');
|
||||
await assertRejected(api.azdata.version(), 'version');
|
||||
|
||||
await assertRejected(api.azdata.arc.dc.create('', '', '', '', '', ''), 'arc dc create');
|
||||
|
||||
await assertRejected(api.azdata.arc.dc.config.list(), 'arc dc config list');
|
||||
await assertRejected(api.azdata.arc.dc.config.show(), 'arc dc config show');
|
||||
|
||||
await assertRejected(api.azdata.arc.dc.endpoint.list(), 'arc dc endpoint list');
|
||||
|
||||
await assertRejected(api.azdata.arc.sql.mi.list(), 'arc sql mi list');
|
||||
await assertRejected(api.azdata.arc.sql.mi.delete(''), 'arc sql mi delete');
|
||||
await assertRejected(api.azdata.arc.sql.mi.show(''), 'arc sql mi show');
|
||||
|
||||
await assertRejected(api.azdata.arc.postgres.server.list(), 'arc sql postgres server list');
|
||||
await assertRejected(api.azdata.arc.postgres.server.delete(''), 'arc sql postgres server delete');
|
||||
await assertRejected(api.azdata.arc.postgres.server.show(''), 'arc sql postgres server show');
|
||||
await assertRejected(api.azdata.arc.postgres.server.edit('', { }), 'arc sql postgres server edit');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,20 +11,14 @@ import * as childProcess from '../common/childProcess';
|
||||
import { HttpClient } from '../common/httpClient';
|
||||
import * as utils from '../common/utils';
|
||||
import * as loc from '../localizedConstants';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import { AzdataReleaseInfo } from '../azdataReleaseInfo';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { eulaAccepted } from '../constants';
|
||||
|
||||
const oldAzdataMock = new azdata.AzdataTool('/path/to/azdata', '0.0.0');
|
||||
const currentAzdataMock = new azdata.AzdataTool('/path/to/azdata', '9999.999.999');
|
||||
|
||||
/**
|
||||
* This matches the schema of the JSON file used to determine the current version of
|
||||
* azdata - do not modify unless also updating the corresponding JSON file
|
||||
*/
|
||||
const releaseJson: AzdataReleaseInfo = {
|
||||
const releaseJson = {
|
||||
win32: {
|
||||
'version': '9999.999.999',
|
||||
'link': 'https://download.com/azdata-20.0.1.msi'
|
||||
@@ -42,212 +36,8 @@ describe('azdata', function () {
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
describe('azdataTool', function (): void {
|
||||
const azdataTool = new azdata.AzdataTool(os.tmpdir(), '1.0.0');
|
||||
let executeCommandStub: sinon.SinonStub;
|
||||
const namespace = 'myNamespace';
|
||||
const name = 'myName';
|
||||
const connectivityMode = 'myConnectivityMode';
|
||||
const resourceGroup = 'myResourceGroup';
|
||||
const location = 'myLocation';
|
||||
const subscription = 'mySubscription';
|
||||
const profileName = 'myProfileName';
|
||||
const storageClass = 'myStorageClass';
|
||||
|
||||
beforeEach(function (): void {
|
||||
executeCommandStub = sinon.stub(childProcess, 'executeCommand').resolves({ stdout: '{}', stderr: '' });
|
||||
});
|
||||
|
||||
describe('arc', function (): void {
|
||||
describe('dc', function (): void {
|
||||
it('create', async function (): Promise<void> {
|
||||
await azdataTool.arc.dc.create(namespace, name, connectivityMode, resourceGroup, location, subscription, profileName, storageClass);
|
||||
verifyExecuteCommandCalledWithArgs([
|
||||
'arc', 'dc', 'create',
|
||||
namespace,
|
||||
name,
|
||||
connectivityMode,
|
||||
resourceGroup,
|
||||
location,
|
||||
subscription,
|
||||
profileName,
|
||||
storageClass]);
|
||||
});
|
||||
describe('endpoint', async function (): Promise<void> {
|
||||
it('list', async function (): Promise<void> {
|
||||
await azdataTool.arc.dc.endpoint.list();
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'endpoint', 'list']);
|
||||
});
|
||||
});
|
||||
describe('config', async function (): Promise<void> {
|
||||
it('list', async function (): Promise<void> {
|
||||
await azdataTool.arc.dc.config.list();
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'list']);
|
||||
});
|
||||
it('show', async function (): Promise<void> {
|
||||
await azdataTool.arc.dc.config.show();
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'show']);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('postgres', function (): void {
|
||||
describe('server', function (): void {
|
||||
it('delete', async function (): Promise<void> {
|
||||
await azdataTool.arc.postgres.server.delete(name);
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'postgres', 'server', 'delete', name]);
|
||||
});
|
||||
it('list', async function (): Promise<void> {
|
||||
await azdataTool.arc.postgres.server.list();
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'postgres', 'server', 'list']);
|
||||
});
|
||||
it('show', async function (): Promise<void> {
|
||||
await azdataTool.arc.postgres.server.show(name);
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'postgres', 'server', 'show', name]);
|
||||
});
|
||||
it('edit', async function (): Promise<void> {
|
||||
const args = {
|
||||
adminPassword: true,
|
||||
coresLimit: 'myCoresLimit',
|
||||
coresRequest: 'myCoresRequest',
|
||||
engineSettings: 'myEngineSettings',
|
||||
extensions: 'myExtensions',
|
||||
memoryLimit: 'myMemoryLimit',
|
||||
memoryRequest: 'myMemoryRequest',
|
||||
noWait: true,
|
||||
port: 1337,
|
||||
replaceEngineSettings: true,
|
||||
workers: 2
|
||||
};
|
||||
await azdataTool.arc.postgres.server.edit(name, args);
|
||||
verifyExecuteCommandCalledWithArgs([
|
||||
'arc', 'postgres', 'server', 'edit',
|
||||
name,
|
||||
'--admin-password',
|
||||
args.coresLimit,
|
||||
args.coresRequest,
|
||||
args.engineSettings,
|
||||
args.extensions,
|
||||
args.memoryLimit,
|
||||
args.memoryRequest,
|
||||
'--no-wait',
|
||||
args.port.toString(),
|
||||
'--replace-engine-settings',
|
||||
args.workers.toString()]);
|
||||
});
|
||||
it('edit no optional args', async function (): Promise<void> {
|
||||
await azdataTool.arc.postgres.server.edit(name, {});
|
||||
verifyExecuteCommandCalledWithArgs([
|
||||
'arc', 'postgres', 'server', 'edit',
|
||||
name]);
|
||||
verifyExecuteCommandCalledWithoutArgs([
|
||||
'--admin-password',
|
||||
'--cores-limit',
|
||||
'--cores-request',
|
||||
'--engine-settings',
|
||||
'--extensions',
|
||||
'--memory-limit',
|
||||
'--memory-request',
|
||||
'--no-wait',
|
||||
'--port',
|
||||
'--replace-engine-settings',
|
||||
'--workers']);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('sql', function (): void {
|
||||
describe('mi', function (): void {
|
||||
it('delete', async function (): Promise<void> {
|
||||
await azdataTool.arc.sql.mi.delete(name);
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'delete', name]);
|
||||
});
|
||||
it('list', async function (): Promise<void> {
|
||||
await azdataTool.arc.sql.mi.list();
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'list']);
|
||||
});
|
||||
it('show', async function (): Promise<void> {
|
||||
await azdataTool.arc.sql.mi.show(name);
|
||||
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'show', name]);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('login', async function (): Promise<void> {
|
||||
const endpoint = 'myEndpoint';
|
||||
const username = 'myUsername';
|
||||
const password = 'myPassword';
|
||||
await azdataTool.login(endpoint, username, password);
|
||||
verifyExecuteCommandCalledWithArgs(['login', endpoint, username]);
|
||||
});
|
||||
it('version', async function (): Promise<void> {
|
||||
executeCommandStub.resolves({ stdout: '1.0.0', stderr: '' });
|
||||
await azdataTool.version();
|
||||
verifyExecuteCommandCalledWithArgs(['--version']);
|
||||
});
|
||||
it('general error throws', async function (): Promise<void> {
|
||||
const err = new Error();
|
||||
executeCommandStub.throws(err);
|
||||
try {
|
||||
await azdataTool.arc.dc.endpoint.list();
|
||||
throw new Error('command should have failed');
|
||||
} catch (error) {
|
||||
should(error).equal(err);
|
||||
}
|
||||
});
|
||||
it('ExitCodeError handled and parsed correctly', async function (): Promise<void> {
|
||||
const errorInnerText = 'my error text';
|
||||
const err = new childProcess.ExitCodeError(1, `ERROR { "stderr": "${errorInnerText}"}`);
|
||||
executeCommandStub.throws(err);
|
||||
try {
|
||||
await azdataTool.arc.dc.endpoint.list();
|
||||
throw new Error('command should have failed');
|
||||
} catch (error) {
|
||||
should(error).equal(err);
|
||||
should((error as childProcess.ExitCodeError).stderr).equal(errorInnerText);
|
||||
}
|
||||
});
|
||||
it('ExitCodeError general error with azdata tool existing rethrows original error', async function (): Promise<void> {
|
||||
sinon.stub(fs.promises, 'access').resolves();
|
||||
const err = new childProcess.ExitCodeError(1, 'some other error');
|
||||
executeCommandStub.throws(err);
|
||||
try {
|
||||
await azdataTool.arc.dc.endpoint.list();
|
||||
throw new Error('command should have failed');
|
||||
} catch (error) {
|
||||
should(error).equal(err);
|
||||
}
|
||||
});
|
||||
it('ExitCodeError general error with azdata tool not existing throws NoAzdataError', async function (): Promise<void> {
|
||||
sinon.stub(fs.promises, 'access').throws(new Error('not found'));
|
||||
const err = new childProcess.ExitCodeError(1, 'some other error');
|
||||
executeCommandStub.throws(err);
|
||||
try {
|
||||
await azdataTool.arc.dc.endpoint.list();
|
||||
throw new Error('command should have failed');
|
||||
} catch (error) {
|
||||
should(error instanceof utils.NoAzdataError).be.true('error should have been instance of NoAzdataError');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Verifies that the specified args were included in the call to executeCommand
|
||||
* @param args The args to check were included in the execute command call
|
||||
*/
|
||||
function verifyExecuteCommandCalledWithArgs(args: string[]): void {
|
||||
const commandArgs = executeCommandStub.args[0][1] as string[];
|
||||
args.forEach(arg => should(commandArgs).containEql(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the specified args weren't included in the call to executeCommand
|
||||
* @param args The args to check weren't included in the execute command call
|
||||
*/
|
||||
function verifyExecuteCommandCalledWithoutArgs(args: string[]): void {
|
||||
const commandArgs = executeCommandStub.args[0][1] as string[];
|
||||
args.forEach(arg => should(commandArgs).not.containEql(arg));
|
||||
}
|
||||
});
|
||||
|
||||
describe('findAzdata', function (): void {
|
||||
describe('findAzdata', function () {
|
||||
it('successful', async function (): Promise<void> {
|
||||
// Mock searchForCmd to return a path to azdata.cmd
|
||||
sinon.stub(utils, 'searchForCmd').returns(Promise.resolve('/path/to/azdata'));
|
||||
@@ -269,9 +59,8 @@ describe('azdata', function () {
|
||||
|
||||
describe('installAzdata', function (): void {
|
||||
|
||||
let errorMessageStub: sinon.SinonStub;
|
||||
beforeEach(function (): void {
|
||||
errorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
sinon.stub(vscode.window, 'showErrorMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
sinon.stub(utils, 'searchForCmd').returns(Promise.resolve('/path/to/azdata'));
|
||||
executeSudoCommandStub = sinon.stub(childProcess, 'executeSudoCommand').returns(Promise.resolve({ stdout: '', stderr: '' }));
|
||||
});
|
||||
@@ -290,42 +79,6 @@ describe('azdata', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped install - dont prompt config', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => 'dontPrompt');
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedInstall();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedInstall();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedInstall();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped install - user chose not to prompt', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
errorMessageStub.resolves(<any>loc.doNotAskAgain);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedInstall();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedInstall();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedInstall();
|
||||
break;
|
||||
}
|
||||
configMock.verify(x => x.update(TypeMoq.It.isAny(), azdata.AzdataDeployOption.dontPrompt, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
it('unsuccessful download - win32', async function (): Promise<void> {
|
||||
sinon.stub(HttpClient, 'downloadFile').rejects();
|
||||
@@ -354,10 +107,8 @@ describe('azdata', function () {
|
||||
});
|
||||
|
||||
describe('updateAzdata', function (): void {
|
||||
let showInformationMessageStub: sinon.SinonStub;
|
||||
|
||||
beforeEach(function (): void {
|
||||
showInformationMessageStub = sinon.stub(vscode.window, 'showInformationMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
sinon.stub(vscode.window, 'showInformationMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
executeSudoCommandStub = sinon.stub(childProcess, 'executeSudoCommand').returns(Promise.resolve({ stdout: '', stderr: '' }));
|
||||
});
|
||||
|
||||
@@ -375,78 +126,6 @@ describe('azdata', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('successful update - always prompt if user requested', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SuccessfulUpdate(true);
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSuccessfulUpdate(true);
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSuccessfulUpdate(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped update - config set not to prompt', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedUpdateDontPrompt();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped update - user chose to never prompt again', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
showInformationMessageStub.resolves(<any>loc.doNotAskAgain);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedUpdateDontPrompt();
|
||||
break;
|
||||
}
|
||||
// Config should have been updated since user chose never to prompt again
|
||||
configMock.verify(x => x.update(TypeMoq.It.isAny(), azdata.AzdataDeployOption.dontPrompt, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
it('skipped update - no new version', async function (): Promise<void> {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedUpdate();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedUpdate();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedUpdate();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped update - no azdata', async function (): Promise<void> {
|
||||
const result = await azdata.checkAndUpdateAzdata();
|
||||
should(result).be.false();
|
||||
});
|
||||
|
||||
it('unsuccessful update', async function (): Promise<void> {
|
||||
switch (process.platform) {
|
||||
@@ -468,81 +147,6 @@ describe('azdata', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('promptForEula', function(): void {
|
||||
it('skipped because of config', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
should(result).be.false();
|
||||
});
|
||||
|
||||
it('always prompt if user requested', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
|
||||
const result = await azdata.promptForEula(mementoMock.object, true);
|
||||
should(result).be.false();
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('prompt if config set to do so', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
should(result).be.false();
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('update config if user chooses not to prompt', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage').resolves(<any>loc.doNotAskAgain);
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
configMock.verify(x => x.update(TypeMoq.It.isAny(), azdata.AzdataDeployOption.dontPrompt, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
should(result).be.false('EULA should not have been accepted');
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('user accepted EULA', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage').resolves(<any>loc.accept);
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
mementoMock.verify(x => x.update(eulaAccepted, true), TypeMoq.Times.once());
|
||||
should(result).be.true('EULA should have been accepted');
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('user accepted EULA - require user action', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showErrorMessage = sinon.stub(vscode.window, 'showErrorMessage').resolves(<any>loc.accept);
|
||||
const result = await azdata.promptForEula(mementoMock.object, true, true);
|
||||
mementoMock.verify(x => x.update(eulaAccepted, true), TypeMoq.Times.once());
|
||||
should(result).be.true('EULA should have been accepted');
|
||||
should(showErrorMessage.calledOnce).be.true('showErrorMessage should have been called to prompt user');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEulaAccepted', function(): void {
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => true);
|
||||
should(azdata.isEulaAccepted(mementoMock.object)).be.true();
|
||||
});
|
||||
});
|
||||
|
||||
async function testLinuxUnsuccessfulUpdate() {
|
||||
@@ -591,16 +195,16 @@ async function testWin32UnsuccessfulUpdate() {
|
||||
should(executeSudoCommandStub.calledOnce).be.true();
|
||||
}
|
||||
|
||||
async function testLinuxSuccessfulUpdate(userRequested = false) {
|
||||
async function testLinuxSuccessfulUpdate() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand').returns(Promise.resolve({ stdout: '0.0.0', stderr: '' }));
|
||||
executeSudoCommandStub.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock, userRequested);
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeSudoCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.calledOnce).be.true();
|
||||
}
|
||||
|
||||
async function testDarwinSuccessfulUpdate(userRequested = false) {
|
||||
async function testDarwinSuccessfulUpdate() {
|
||||
const brewInfoOutput = [{
|
||||
name: 'azdata-cli',
|
||||
full_name: 'microsoft/azdata-cli-release/azdata-cli',
|
||||
@@ -618,136 +222,21 @@ async function testDarwinSuccessfulUpdate(userRequested = false) {
|
||||
stdout: JSON.stringify(brewInfoOutput)
|
||||
})
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock, userRequested);
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.getCall(2).args[0]).be.equal('brew', '3rd call should have been to brew');
|
||||
should(executeCommandStub.getCall(2).args[1]).deepEqual(['info', 'azdata-cli', '--json'], '3rd call did not have expected arguments');
|
||||
}
|
||||
|
||||
|
||||
async function testWin32SuccessfulUpdate(userRequested = false) {
|
||||
async function testWin32SuccessfulUpdate() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock, userRequested);
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeSudoCommandStub.calledOnce).be.true('executeSudoCommand should have been called once');
|
||||
should(executeSudoCommandStub.getCall(0).args[0]).startWith('msiexec /qn /i');
|
||||
}
|
||||
|
||||
async function testLinuxSkippedUpdate() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
executeSudoCommandStub.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(currentAzdataMock);
|
||||
should(executeSudoCommandStub.callCount).be.equal(0, 'executeSudoCommand was not expected to be called');
|
||||
}
|
||||
|
||||
async function testDarwinSkippedUpdateDontPrompt() {
|
||||
const brewInfoOutput = [{
|
||||
name: 'azdata-cli',
|
||||
full_name: 'microsoft/azdata-cli-release/azdata-cli',
|
||||
versions: {
|
||||
'stable': '9999.999.999',
|
||||
'devel': null,
|
||||
'head': null,
|
||||
'bottle': true
|
||||
}
|
||||
}];
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand')
|
||||
.onThirdCall() //third call is brew info azdata-cli --json which needs to return json of new available azdata versions.
|
||||
.resolves({
|
||||
stderr: '',
|
||||
stdout: JSON.stringify(brewInfoOutput)
|
||||
})
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.notCalledWith(sinon.match.any, sinon.match.array.contains(['upgrade', 'azdata-cli'])));
|
||||
}
|
||||
|
||||
async function testWin32SkippedUpdateDontPrompt() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeSudoCommandStub.notCalled).be.true('executeSudoCommand should not have been called');
|
||||
}
|
||||
|
||||
async function testLinuxSkippedUpdateDontPrompt() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(childProcess, 'executeCommand').returns(Promise.resolve({ stdout: '0.0.0', stderr: '' }));
|
||||
executeSudoCommandStub.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeSudoCommandStub.callCount).be.equal(0, 'executeSudoCommand was not expected to be called');
|
||||
}
|
||||
|
||||
async function testDarwinSkippedUpdate() {
|
||||
const brewInfoOutput = [{
|
||||
name: 'azdata-cli',
|
||||
full_name: 'microsoft/azdata-cli-release/azdata-cli',
|
||||
versions: {
|
||||
'stable': '9999.999.999',
|
||||
'devel': null,
|
||||
'head': null,
|
||||
'bottle': true
|
||||
}
|
||||
}];
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand')
|
||||
.onThirdCall() //third call is brew info azdata-cli --json which needs to return json of new available azdata versions.
|
||||
.resolves({
|
||||
stderr: '',
|
||||
stdout: JSON.stringify(brewInfoOutput)
|
||||
})
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(currentAzdataMock);
|
||||
should(executeCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.notCalledWith(sinon.match.any, sinon.match.array.contains(['upgrade', 'azdata-cli'])));
|
||||
}
|
||||
|
||||
async function testWin32SkippedUpdate() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
await azdata.checkAndUpdateAzdata(currentAzdataMock);
|
||||
should(executeSudoCommandStub.notCalled).be.true('executeSudoCommand should not have been called');
|
||||
}
|
||||
|
||||
async function testDarwinSkippedInstall() {
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand')
|
||||
.onFirstCall()
|
||||
.callsFake(async (_command: string, _args: string[]) => {
|
||||
return Promise.reject(new Error('not Found'));
|
||||
})
|
||||
.callsFake(async (_command: string, _args: string[]) => {
|
||||
return Promise.resolve({ stdout: '0.0.0', stderr: '' });
|
||||
});
|
||||
const result = await azdata.checkAndInstallAzdata();
|
||||
should(result).equal(undefined, 'result should be undefined');
|
||||
should(executeCommandStub.callCount).be.equal(0);
|
||||
}
|
||||
|
||||
async function testLinuxSkippedInstall() {
|
||||
sinon.stub(childProcess, 'executeCommand')
|
||||
.onFirstCall()
|
||||
.rejects(new Error('not Found'))
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
executeSudoCommandStub
|
||||
.resolves({ stdout: 'success', stderr: '' });
|
||||
const result = await azdata.checkAndInstallAzdata();
|
||||
should(result).equal(undefined, 'result should be undefined');
|
||||
should(executeSudoCommandStub.callCount).be.equal(0);
|
||||
}
|
||||
|
||||
async function testWin32SkippedInstall() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
sinon.stub(childProcess, 'executeCommand')
|
||||
.onFirstCall()
|
||||
.rejects(new Error('not Found')) // First call mock the tool not being found
|
||||
.resolves({ stdout: '1.0.0', stderr: '' });
|
||||
executeSudoCommandStub
|
||||
.returns({ stdout: '', stderr: '' });
|
||||
const result = await azdata.checkAndInstallAzdata();
|
||||
should(result).equal(undefined, 'result should be undefined');
|
||||
should(executeSudoCommandStub.notCalled).be.true('executeSudoCommand should not have been called');
|
||||
}
|
||||
|
||||
async function testWin32SuccessfulInstall() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import { HttpClient } from '../common/httpClient';
|
||||
import { getPlatformReleaseVersion, getPlatformDownloadLink, AzdataReleaseInfo } from '../azdataReleaseInfo';
|
||||
|
||||
const emptyReleaseJson = {
|
||||
win32: {},
|
||||
darwin: {},
|
||||
linux: {}
|
||||
};
|
||||
|
||||
const releaseVersion = '999.999.999';
|
||||
const releaseLink = 'https://microsoft.com';
|
||||
|
||||
const validReleaseJson: AzdataReleaseInfo = {
|
||||
win32: {
|
||||
version: releaseVersion,
|
||||
link: releaseLink
|
||||
},
|
||||
darwin: {
|
||||
version: releaseVersion,
|
||||
link: releaseLink
|
||||
},
|
||||
linux: {
|
||||
version: releaseVersion,
|
||||
link: releaseLink
|
||||
}
|
||||
};
|
||||
|
||||
describe('azdataReleaseInfo', function (): void {
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('getPlatformReleaseVersion', function(): void {
|
||||
it('gets version successfully', async function(): Promise<void> {
|
||||
sinon.stub(HttpClient, 'getTextContent').resolves(JSON.stringify(validReleaseJson));
|
||||
const version = await getPlatformReleaseVersion();
|
||||
should(version.format()).equal(releaseVersion);
|
||||
});
|
||||
|
||||
it('throws with invalid JSON', async function (): Promise<void> {
|
||||
sinon.stub(HttpClient, 'getTextContent').resolves('invalid JSON');
|
||||
await should(getPlatformReleaseVersion()).be.rejected();
|
||||
});
|
||||
|
||||
it('throws when no version', async function (): Promise<void> {
|
||||
sinon.stub(HttpClient, 'getTextContent').resolves(JSON.stringify(emptyReleaseJson));
|
||||
await should(getPlatformReleaseVersion()).be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPlatformDownloadLink', function(): void {
|
||||
it('gets link successfully', async function(): Promise<void> {
|
||||
sinon.stub(HttpClient, 'getTextContent').resolves(JSON.stringify(validReleaseJson));
|
||||
const link = await getPlatformDownloadLink();
|
||||
should(link).equal(releaseLink);
|
||||
});
|
||||
|
||||
it('throws with invalid JSON', async function (): Promise<void> {
|
||||
sinon.stub(HttpClient, 'getTextContent').resolves('invalid JSON');
|
||||
await should(getPlatformDownloadLink()).be.rejected();
|
||||
});
|
||||
|
||||
it('throws when no version', async function (): Promise<void> {
|
||||
sinon.stub(HttpClient, 'getTextContent').resolves(JSON.stringify(emptyReleaseJson));
|
||||
await should(getPlatformDownloadLink()).be.rejected();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdataExt from 'azdata-ext';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import { ArcControllerConfigProfilesOptionsSource } from '../../providers/arcControllerConfigProfilesOptionsSource';
|
||||
|
||||
describe('arcControllerConfigProfilesOptionsSource', async function (): Promise<void> {
|
||||
afterEach(function(): void {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('eula accepted returns list', async function (): Promise<void> {
|
||||
const options = ['option1', 'option2'];
|
||||
const api = vscode.extensions.getExtension(azdataExt.extension.name)?.exports as azdataExt.IExtension;
|
||||
sinon.stub(api, 'isEulaAccepted').resolves(true);
|
||||
sinon.stub(api.azdata.arc.dc.config, 'list').resolves({ stdout: [''], stderr: [''], logs: [''], result: options});
|
||||
const source = new ArcControllerConfigProfilesOptionsSource(api);
|
||||
const result = await source.getOptions();
|
||||
should(result).deepEqual(options);
|
||||
});
|
||||
|
||||
it('eula not accepted prompts for acceptance', async function (): Promise<void> {
|
||||
const options = ['option1', 'option2'];
|
||||
const api = vscode.extensions.getExtension(azdataExt.extension.name)?.exports as azdataExt.IExtension;
|
||||
sinon.stub(api, 'isEulaAccepted').resolves(false);
|
||||
const promptStub = sinon.stub(api, 'promptForEula').resolves(true);
|
||||
sinon.stub(api.azdata.arc.dc.config, 'list').resolves({ stdout: [''], stderr: [''], logs: [''], result: options});
|
||||
const source = new ArcControllerConfigProfilesOptionsSource(api);
|
||||
const result = await source.getOptions();
|
||||
should(result).deepEqual(options);
|
||||
should(promptStub.calledOnce).be.true('promptForEula should have been called');
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import { AzdataTool } from '../../azdata';
|
||||
import { AzdataToolService } from '../../services/azdataToolService';
|
||||
|
||||
describe('azdataToolService', function (): void {
|
||||
it('Tool should be set correctly', async function (): Promise<void> {
|
||||
const service = new AzdataToolService();
|
||||
should(service.localAzdata).be.undefined();
|
||||
service.localAzdata = new AzdataTool('my path', '1.0.0');
|
||||
should(service).not.be.undefined();
|
||||
});
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Asserts that the specified promise was rejected. This is similar to should(..).be.rejected but
|
||||
* allows specifying a message in the thrown Error to add more information to the failure.
|
||||
* @param promise The promise to verify was rejected
|
||||
* @param message The message to include in the error if the promise isn't rejected
|
||||
*/
|
||||
export async function assertRejected(promise: Promise<any>, message: string): Promise<void> {
|
||||
try {
|
||||
await promise;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
@@ -172,8 +172,7 @@ declare module 'azdata-ext' {
|
||||
}
|
||||
},
|
||||
scale: {
|
||||
shards: number, // 1 (shards was renamed to workers, kept here for backwards compatibility)
|
||||
workers: number // 1
|
||||
shards: number // 1
|
||||
},
|
||||
scheduling: {
|
||||
default: {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"resourceViewResources": [
|
||||
{
|
||||
"id": "azure-resources",
|
||||
"name": "%azure.resource.view.title%",
|
||||
"name": "Azure",
|
||||
"icon": "./resources/azure.svg"
|
||||
}
|
||||
],
|
||||
@@ -37,7 +37,7 @@
|
||||
"description": "%azure.resource.config.filter.description%"
|
||||
},
|
||||
"azure.tenant.config.filter": {
|
||||
"type": "array",
|
||||
"type":"array",
|
||||
"default": [],
|
||||
"description": "%azure.tenant.config.filter.description%"
|
||||
}
|
||||
@@ -94,6 +94,11 @@
|
||||
"type": "object",
|
||||
"title": "Azure",
|
||||
"properties": {
|
||||
"azure.enableArcFeatures": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.enableArcFeatures%"
|
||||
},
|
||||
"azure.noSystemKeychain": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
@@ -174,23 +179,21 @@
|
||||
"dark": "resources/dark/add_to_server_list_inverse.svg",
|
||||
"light": "resources/light/add_to_server_list.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "azure.dataGrid.openInAzurePortal",
|
||||
"title": "%azure.openInAzurePortal.title%"
|
||||
}
|
||||
],
|
||||
"connectionTreeProvider": [
|
||||
{
|
||||
"id": "connectionDialog/azureResourceExplorer",
|
||||
"name": "%azure.resource.explorer.title%"
|
||||
}
|
||||
],
|
||||
"dataExplorer": {
|
||||
"dialog/connection": [
|
||||
{
|
||||
"id": "azureResourceExplorer_dialog",
|
||||
"name": "%azure.resource.explorer.title%",
|
||||
"when": "config.connection.dialog.browse"
|
||||
}
|
||||
],
|
||||
"dataExplorer": [
|
||||
{
|
||||
"id": "azureResourceExplorer",
|
||||
"name": "%azure.resource.explorer.title%"
|
||||
"name": "%azure.resource.explorer.title%",
|
||||
"when": "!config.connection.dialog.browse"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -215,10 +218,6 @@
|
||||
{
|
||||
"command": "azure.resource.connectsqlserver",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "azure.dataGrid.openInAzurePortal",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"view/title": [
|
||||
@@ -279,33 +278,6 @@
|
||||
"when": "viewItem == azure.resource.itemType.account",
|
||||
"group": "azurecore"
|
||||
}
|
||||
],
|
||||
"connectionDialog/browseTree": [
|
||||
{
|
||||
"command": "azure.resource.selectsubscriptions",
|
||||
"when": "contextValue == azure.resource.itemType.account",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.refresh",
|
||||
"when": "contextValue == azure.resource.itemType.account",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.signin",
|
||||
"when": "treeId == connectionDialog/azureResourceExplorer",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.refreshall",
|
||||
"when": "treeId == connectionDialog/azureResourceExplorer",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"dataGrid/item/context": [
|
||||
{
|
||||
"command": "azure.dataGrid.openInAzurePortal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hasAzureResourceProviders": true
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
"azure.resource.startterminal.title": "Start Cloud Shell",
|
||||
"azure.resource.connectsqlserver.title": "Connect",
|
||||
"azure.resource.connectsqldb.title": "Add to Servers",
|
||||
"azure.resource.view.title": "Azure (Preview)",
|
||||
"azure.tenant.config.filter.description": "The list of tenant IDs to ignore when querying azure resources. Each element is a tenant id.",
|
||||
|
||||
"accounts.clearTokenCache": "Clear Azure Account Token Cache",
|
||||
@@ -30,5 +29,6 @@
|
||||
"config.azureCodeGrantMethod": "Code Grant Method",
|
||||
"config.azureDeviceCodeMethod": "Device Code Method",
|
||||
"config.noSystemKeychain": "Disable system keychain integration. Credentials will be stored in a flat file in the user's home directory.",
|
||||
"config.enableArcFeatures": "Should features related to Azure Arc be enabled (preview)",
|
||||
"config.piiLogging": "Should Personally Identifiable Information (PII) be logged in the console view locally"
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@ export class AzureAccountProvider implements azdata.AccountProvider, vscode.Disp
|
||||
|
||||
private async _initialize(storedAccounts: azdata.Account[]): Promise<azdata.Account[]> {
|
||||
const accounts: azdata.Account[] = [];
|
||||
console.log(`Initializing stored accounts ${JSON.stringify(accounts)}`);
|
||||
for (let account of storedAccounts) {
|
||||
const azureAuth = this.getAuthMethod(account);
|
||||
if (!azureAuth) {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { AppContext } from './appContext';
|
||||
import { AzureResourceServiceNames } from './azureResource/constants';
|
||||
import { IAzureResourceSubscriptionService } from './azureResource/interfaces';
|
||||
import { TokenCredentials } from '@azure/ms-rest-js';
|
||||
import { azureResource } from 'azureResource';
|
||||
import * as azureResourceUtils from './azureResource/utils';
|
||||
import * as constants from './constants';
|
||||
import * as loc from './localizedConstants';
|
||||
import * as utils from './utils';
|
||||
|
||||
const typesClause = [
|
||||
azureResource.AzureResourceType.sqlDatabase,
|
||||
azureResource.AzureResourceType.sqlServer,
|
||||
azureResource.AzureResourceType.sqlManagedInstance,
|
||||
azureResource.AzureResourceType.postgresServer,
|
||||
azureResource.AzureResourceType.azureArcService,
|
||||
azureResource.AzureResourceType.azureArcSqlManagedInstance,
|
||||
azureResource.AzureResourceType.azureArcPostgresServer
|
||||
].map(type => `type == "${type}"`).join(' or ');
|
||||
|
||||
export class AzureDataGridProvider implements azdata.DataGridProvider {
|
||||
constructor(private _appContext: AppContext) { }
|
||||
|
||||
public providerId = constants.dataGridProviderId;
|
||||
public title = loc.azureResourcesGridTitle;
|
||||
|
||||
public async getDataGridItems() {
|
||||
const accounts = await azdata.accounts.getAllAccounts();
|
||||
const items: any[] = [];
|
||||
await Promise.all(accounts.map(async (account) => {
|
||||
await Promise.all(account.properties.tenants.map(async (tenant: { id: string; }) => {
|
||||
try {
|
||||
const tokenResponse = await azdata.accounts.getAccountSecurityToken(account, tenant.id, azdata.AzureResource.ResourceManagement);
|
||||
const token = tokenResponse.token;
|
||||
const tokenType = tokenResponse.tokenType;
|
||||
const credential = new TokenCredentials(token, tokenType);
|
||||
const subscriptionService = this._appContext.getService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService);
|
||||
const subscriptions = await subscriptionService.getSubscriptions(account, credential, tenant.id);
|
||||
try {
|
||||
const newItems = (await azureResourceUtils.runResourceQuery(account, subscriptions, true, `where ${typesClause}`)).resources
|
||||
.map(item => {
|
||||
return <azdata.DataGridItem>{
|
||||
id: item.id,
|
||||
// Property values
|
||||
name: item.name,
|
||||
resourceGroup: item.resourceGroup,
|
||||
subscriptionId: item.subscriptionId,
|
||||
subscriptionName: subscriptions.find(subscription => subscription.id === item.subscriptionId)?.name ?? item.subscriptionId,
|
||||
locationDisplayName: utils.getRegionDisplayName(item.location),
|
||||
type: item.type,
|
||||
typeDisplayName: utils.getResourceTypeDisplayName(item.type),
|
||||
iconPath: utils.getResourceTypeIcon(this._appContext, item.type),
|
||||
portalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
};
|
||||
});
|
||||
items.push(...newItems);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}));
|
||||
}));
|
||||
return items;
|
||||
}
|
||||
|
||||
public async getDataGridColumns(): Promise<azdata.DataGridColumn[]> {
|
||||
return [
|
||||
{ id: 'icon', type: 'image', field: 'iconPath', name: '', width: 25, sortable: false, filterable: false, resizable: false, tooltip: loc.typeIcon },
|
||||
{ id: 'name', type: 'text', field: 'name', name: loc.name, width: 150 },
|
||||
{ id: 'type', type: 'text', field: 'typeDisplayName', name: loc.resourceType, width: 150 },
|
||||
{ id: 'type', type: 'text', field: 'resourceGroup', name: loc.resourceGroup, width: 150 },
|
||||
{ id: 'location', type: 'text', field: 'locationDisplayName', name: loc.location, width: 150 },
|
||||
{ id: 'subscriptionId', type: 'text', field: 'subscriptionName', name: loc.subscription, width: 150 }
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ declare module 'azureResource' {
|
||||
sqlServer = 'microsoft.sql/servers',
|
||||
sqlDatabase = 'microsoft.sql/servers/databases',
|
||||
sqlManagedInstance = 'microsoft.sql/managedinstances',
|
||||
azureArcSqlManagedInstance = 'microsoft.azuredata/sqlmanagedinstances',
|
||||
azureArcSqlManagedInstance = 'microsoft.azuredata/sqlinstances',
|
||||
virtualMachines = 'microsoft.compute/virtualmachines',
|
||||
kustoClusters = 'microsoft.kusto/clusters',
|
||||
azureArcPostgresServer = 'microsoft.azuredata/postgresinstances',
|
||||
@@ -26,7 +26,6 @@ declare module 'azureResource' {
|
||||
}
|
||||
|
||||
export interface IAzureResourceTreeDataProvider extends TreeDataProvider<IAzureResourceNode> {
|
||||
browseConnectionMode: boolean;
|
||||
}
|
||||
|
||||
export interface IAzureResourceNode {
|
||||
@@ -36,29 +35,22 @@ declare module 'azureResource' {
|
||||
readonly treeItem: TreeItem;
|
||||
}
|
||||
|
||||
export interface IAzureSubscriptionInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AzureResource {
|
||||
name: string;
|
||||
id: string;
|
||||
subscription: IAzureSubscriptionInfo;
|
||||
resourceGroup?: string;
|
||||
subscriptionId: string;
|
||||
tenant?: string;
|
||||
}
|
||||
|
||||
export interface AzureResourceSubscription extends Omit<AzureResource, 'subscription'> {
|
||||
export interface AzureResourceSubscription extends Omit<AzureResource, 'subscriptionId'> {
|
||||
}
|
||||
|
||||
export interface AzureSqlResource extends AzureResource {
|
||||
loginName: string;
|
||||
}
|
||||
|
||||
export interface AzureGraphResource extends Omit<AzureResource, 'tenant' | 'subscription'> {
|
||||
export interface AzureGraphResource extends Omit<AzureResource, 'tenant'> {
|
||||
tenantId: string;
|
||||
subscriptionId: string;
|
||||
type: string;
|
||||
location: string;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,8 @@ import { AzureResourceAccountTreeNode } from './tree/accountTreeNode';
|
||||
import { IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterService, IAzureTerminalService } from '../azureResource/interfaces';
|
||||
import { AzureResourceServiceNames } from './constants';
|
||||
import { AzureAccount, Tenant } from '../account-provider/interfaces';
|
||||
import { FlatAccountTreeNode } from './tree/flatAccountTreeNode';
|
||||
import { ConnectionDialogTreeProvider } from './tree/connectionDialogTreeProvider';
|
||||
|
||||
export function registerAzureResourceCommands(appContext: AppContext, trees: (AzureResourceTreeProvider | ConnectionDialogTreeProvider)[]): void {
|
||||
export function registerAzureResourceCommands(appContext: AppContext, tree: AzureResourceTreeProvider): void {
|
||||
vscode.commands.registerCommand('azure.resource.startterminal', async (node?: TreeNode) => {
|
||||
try {
|
||||
const enablePreviewFeatures = vscode.workspace.getConfiguration('workbench').get('enablePreviewFeatures');
|
||||
@@ -30,35 +28,14 @@ export function registerAzureResourceCommands(appContext: AppContext, trees: (Az
|
||||
vscode.window.showInformationMessage(msg);
|
||||
return;
|
||||
}
|
||||
let azureAccount: AzureAccount | undefined;
|
||||
if (node instanceof AzureResourceAccountTreeNode) {
|
||||
azureAccount = node.account as AzureAccount;
|
||||
} else {
|
||||
let accounts = await azdata.accounts.getAllAccounts();
|
||||
accounts = accounts.filter(a => a.key.providerId.startsWith('azure'));
|
||||
if (accounts.length === 0) {
|
||||
const signin = localize('azure.signIn', "Sign in");
|
||||
const action = await vscode.window.showErrorMessage(localize('azure.noAccountError', "You are not currently signed into any Azure accounts, Please sign in and then try again."),
|
||||
signin);
|
||||
if (action === signin) {
|
||||
vscode.commands.executeCommand('azure.resource.signin');
|
||||
}
|
||||
return;
|
||||
} else if (accounts.length === 1) {
|
||||
azureAccount = accounts[0];
|
||||
} else {
|
||||
const pickedAccount = await vscode.window.showQuickPick(accounts.map(account => account.displayInfo.displayName), {
|
||||
canPickMany: false,
|
||||
placeHolder: localize('azure.pickAnAzureAccount', "Select an Azure account")
|
||||
});
|
||||
if (!pickedAccount) {
|
||||
vscode.window.showErrorMessage(localize('azure.accountNotSelectedError', "You must select an Azure account for this feature to work."));
|
||||
return;
|
||||
}
|
||||
azureAccount = accounts.find(acct => acct.displayInfo.displayName === pickedAccount);
|
||||
}
|
||||
if (!node || !(node instanceof AzureResourceAccountTreeNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const accountNode = node as AzureResourceAccountTreeNode;
|
||||
const azureAccount = accountNode.account as AzureAccount;
|
||||
|
||||
|
||||
const terminalService = appContext.getService<IAzureTerminalService>(AzureResourceServiceNames.terminalService);
|
||||
|
||||
const listOfTenants = azureAccount.properties.tenants.map(t => t.displayName);
|
||||
@@ -96,7 +73,7 @@ export function registerAzureResourceCommands(appContext: AppContext, trees: (Az
|
||||
// Resource Tree commands
|
||||
|
||||
vscode.commands.registerCommand('azure.resource.selectsubscriptions', async (node?: TreeNode) => {
|
||||
if (!(node instanceof AzureResourceAccountTreeNode) && !(node instanceof FlatAccountTreeNode)) {
|
||||
if (!(node instanceof AzureResourceAccountTreeNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,7 +85,9 @@ export function registerAzureResourceCommands(appContext: AppContext, trees: (Az
|
||||
const subscriptionService = appContext.getService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService);
|
||||
const subscriptionFilterService = appContext.getService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService);
|
||||
|
||||
const subscriptions = [];
|
||||
const accountNode = node as AzureResourceAccountTreeNode;
|
||||
|
||||
const subscriptions = (await accountNode.getCachedSubscriptions()) || <azureResource.AzureResourceSubscription[]>[];
|
||||
if (subscriptions.length === 0) {
|
||||
try {
|
||||
|
||||
@@ -126,7 +105,7 @@ export function registerAzureResourceCommands(appContext: AppContext, trees: (Az
|
||||
}
|
||||
}
|
||||
|
||||
let selectedSubscriptions = await subscriptionFilterService.getSelectedSubscriptions(account);
|
||||
let selectedSubscriptions = await subscriptionFilterService.getSelectedSubscriptions(accountNode.account);
|
||||
if (!selectedSubscriptions) {
|
||||
selectedSubscriptions = [];
|
||||
}
|
||||
@@ -153,25 +132,17 @@ export function registerAzureResourceCommands(appContext: AppContext, trees: (Az
|
||||
|
||||
const selectedSubscriptionQuickPickItems = await vscode.window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true });
|
||||
if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) {
|
||||
for (const tree of trees) {
|
||||
await tree.refresh(undefined, false);
|
||||
}
|
||||
await tree.refresh(node, false);
|
||||
|
||||
selectedSubscriptions = selectedSubscriptionQuickPickItems.map((subscriptionItem) => subscriptionItem.subscription);
|
||||
await subscriptionFilterService.saveSelectedSubscriptions(account, selectedSubscriptions);
|
||||
await subscriptionFilterService.saveSelectedSubscriptions(accountNode.account, selectedSubscriptions);
|
||||
}
|
||||
});
|
||||
|
||||
vscode.commands.registerCommand('azure.resource.refreshall', () => {
|
||||
for (const tree of trees) {
|
||||
tree.notifyNodeChanged(undefined);
|
||||
}
|
||||
});
|
||||
vscode.commands.registerCommand('azure.resource.refreshall', () => tree.notifyNodeChanged(undefined));
|
||||
|
||||
vscode.commands.registerCommand('azure.resource.refresh', async (node?: TreeNode) => {
|
||||
for (const tree of trees) {
|
||||
await tree.refresh(node, true);
|
||||
}
|
||||
await tree.refresh(node, true);
|
||||
});
|
||||
|
||||
vscode.commands.registerCommand('azure.resource.signin', async (node?: TreeNode) => {
|
||||
|
||||
@@ -51,12 +51,8 @@ export class AzureResourceDatabaseService implements IAzureResourceService<azure
|
||||
serverName: server.name,
|
||||
serverFullName: server.properties.fullyQualifiedDomainName,
|
||||
loginName: server.properties.administratorLogin,
|
||||
subscription: {
|
||||
id: db.subscriptionId,
|
||||
name: (subscriptions.find(sub => sub.id === db.subscriptionId))?.name
|
||||
},
|
||||
tenant: db.tenantId,
|
||||
resourceGroup: db.resourceGroup
|
||||
subscriptionId: db.subscriptionId,
|
||||
tenant: db.tenantId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ export class AzureResourceDatabaseTreeDataProvider extends ResourceTreeDataProvi
|
||||
protected getTreeItemForResource(database: azureResource.AzureResourceDatabase, account: Account): TreeItem {
|
||||
return {
|
||||
id: `databaseServer_${database.serverFullName}.database_${database.name}`,
|
||||
label: this.browseConnectionMode ? `${database.serverName}/${database.name} (${AzureResourceDatabaseTreeDataProvider.containerLabel}, ${database.subscription.name})` : `${database.name} (${database.serverName})`,
|
||||
label: `${database.name} (${database.serverName})`,
|
||||
iconPath: {
|
||||
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_database_inverse.svg'),
|
||||
light: this._extensionContext.asAbsolutePath('resources/light/sql_database.svg')
|
||||
},
|
||||
collapsibleState: this.browseConnectionMode ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
|
||||
collapsibleState: vscode.workspace.getConfiguration('connection').get<boolean>('dialog.browse') ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
|
||||
contextValue: AzureResourceItemType.database,
|
||||
payload: {
|
||||
id: generateGuid(),
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { ResourceServiceBase, GraphData } from '../resourceTreeDataProviderBase';
|
||||
import { azureResource } from 'azureResource';
|
||||
|
||||
|
||||
export interface DbServerGraphData extends GraphData {
|
||||
properties: {
|
||||
fullyQualifiedDomainName: string;
|
||||
@@ -29,12 +30,8 @@ export class AzureResourceDatabaseServerService extends ResourceServiceBase<DbSe
|
||||
fullName: resource.properties.fullyQualifiedDomainName,
|
||||
loginName: resource.properties.administratorLogin,
|
||||
defaultDatabaseName: 'master',
|
||||
subscription: {
|
||||
id: resource.subscriptionId,
|
||||
name: resource.subscriptionName
|
||||
},
|
||||
tenant: resource.tenantId,
|
||||
resourceGroup: resource.resourceGroup
|
||||
subscriptionId: resource.subscriptionId,
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ export class AzureResourceDatabaseServerTreeDataProvider extends ResourceTreeDat
|
||||
protected getTreeItemForResource(databaseServer: azureResource.AzureResourceDatabaseServer, account: Account): TreeItem {
|
||||
return {
|
||||
id: `databaseServer_${databaseServer.id ? databaseServer.id : databaseServer.name}`,
|
||||
label: this.browseConnectionMode ? `${databaseServer.name} (${AzureResourceDatabaseServerTreeDataProvider.containerLabel}, ${databaseServer.subscription.name})` : databaseServer.name,
|
||||
label: databaseServer.name,
|
||||
iconPath: {
|
||||
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_server_inverse.svg'),
|
||||
light: this._extensionContext.asAbsolutePath('resources/light/sql_server.svg')
|
||||
},
|
||||
collapsibleState: this.browseConnectionMode ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
|
||||
collapsibleState: vscode.workspace.getConfiguration('connection').get<boolean>('dialog.browse') ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
|
||||
contextValue: AzureResourceItemType.databaseServer,
|
||||
payload: {
|
||||
id: generateGuid(),
|
||||
|
||||
@@ -29,12 +29,8 @@ export class KustoResourceService extends ResourceServiceBase<KustoGraphData, az
|
||||
fullName: resource.properties.uri.replace('https://', ''),
|
||||
loginName: '',
|
||||
defaultDatabaseName: '',
|
||||
subscription: {
|
||||
id: resource.subscriptionId,
|
||||
name: resource.subscriptionName
|
||||
},
|
||||
tenant: resource.tenantId,
|
||||
resourceGroup: resource.resourceGroup
|
||||
subscriptionId: resource.subscriptionId,
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionNodeType, TreeItem, Account } from 'azdata';
|
||||
import { TreeItemCollapsibleState, ExtensionContext } from 'vscode';
|
||||
import { TreeItemCollapsibleState, ExtensionContext, workspace } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -16,7 +16,7 @@ import { azureResource } from 'azureResource';
|
||||
|
||||
export class KustoTreeDataProvider extends ResourceTreeDataProviderBase<azureResource.AzureResourceDatabaseServer> {
|
||||
private static readonly containerId = 'azure.resource.providers.KustoContainer';
|
||||
private static readonly containerLabel = localize('azure.resource.providers.KustoContainerLabel', "Azure Data Explorer Cluster");
|
||||
private static readonly containerLabel = localize('azure.resource.providers.KustoContainerLabel', "Azure Data Explorer Clusters");
|
||||
|
||||
public constructor(
|
||||
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
|
||||
@@ -29,12 +29,12 @@ export class KustoTreeDataProvider extends ResourceTreeDataProviderBase<azureRes
|
||||
protected getTreeItemForResource(databaseServer: azureResource.AzureResourceDatabaseServer, account: Account): TreeItem {
|
||||
return {
|
||||
id: `Kusto_${databaseServer.id ? databaseServer.id : databaseServer.name}`,
|
||||
label: this.browseConnectionMode ? `${databaseServer.name} (${KustoTreeDataProvider.containerLabel}, ${databaseServer.subscription.name})` : databaseServer.name,
|
||||
label: databaseServer.name,
|
||||
iconPath: {
|
||||
dark: this._extensionContext.asAbsolutePath('resources/dark/azureDE_inverse.svg'),
|
||||
light: this._extensionContext.asAbsolutePath('resources/light/azureDE.svg')
|
||||
},
|
||||
collapsibleState: this.browseConnectionMode ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed,
|
||||
collapsibleState: workspace.getConfiguration('connection').get<boolean>('dialog.browse') ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed,
|
||||
contextValue: AzureResourceItemType.azureDataExplorer,
|
||||
payload: {
|
||||
id: generateGuid(),
|
||||
|
||||
@@ -27,12 +27,8 @@ export class PostgresServerArcService extends ResourceServiceBase<PostgresArcSer
|
||||
fullName: resource.name,
|
||||
loginName: resource.properties.admin,
|
||||
defaultDatabaseName: 'postgres',
|
||||
subscription: {
|
||||
id: resource.subscriptionId,
|
||||
name: resource.subscriptionName
|
||||
},
|
||||
tenant: resource.tenantId,
|
||||
resourceGroup: resource.resourceGroup
|
||||
subscriptionId: resource.subscriptionId,
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionNodeType, TreeItem, Account } from 'azdata';
|
||||
import { TreeItemCollapsibleState, ExtensionContext } from 'vscode';
|
||||
import { TreeItemCollapsibleState, ExtensionContext, workspace } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -29,12 +29,12 @@ export class PostgresServerArcTreeDataProvider extends ResourceTreeDataProviderB
|
||||
protected getTreeItemForResource(databaseServer: azureResource.AzureResourceDatabaseServer, account: Account): TreeItem {
|
||||
return {
|
||||
id: `databaseServer_${databaseServer.id ? databaseServer.id : databaseServer.name}`,
|
||||
label: this.browseConnectionMode ? `${databaseServer.name} (${PostgresServerArcTreeDataProvider.containerLabel}, ${databaseServer.subscription.name})` : databaseServer.name,
|
||||
label: databaseServer.name,
|
||||
iconPath: {
|
||||
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_server_inverse.svg'),
|
||||
light: this._extensionContext.asAbsolutePath('resources/light/sql_server.svg')
|
||||
},
|
||||
collapsibleState: this.browseConnectionMode ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed,
|
||||
collapsibleState: workspace.getConfiguration('connection').get<boolean>('dialog.browse') ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed,
|
||||
contextValue: AzureResourceItemType.databaseServer,
|
||||
payload: {
|
||||
id: generateGuid(),
|
||||
|
||||
@@ -30,12 +30,8 @@ export class PostgresServerService extends ResourceServiceBase<DbServerGraphData
|
||||
fullName: resource.properties.fullyQualifiedDomainName,
|
||||
loginName: resource.properties.administratorLogin,
|
||||
defaultDatabaseName: 'postgres',
|
||||
subscription: {
|
||||
id: resource.subscriptionId,
|
||||
name: resource.subscriptionName
|
||||
},
|
||||
tenant: resource.tenantId,
|
||||
resourceGroup: resource.resourceGroup
|
||||
subscriptionId: resource.subscriptionId,
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user