Skip to content

Commit

Permalink
Users/rok/mysql task (#6251)
Browse files Browse the repository at this point in the history
* mysql tasks

* Mysql task

* After testing on linux Azure VM

* sql path location

* after refactoring

* unused code

* after changing message

* refactored code

* Api comment and documentations

* after added newline at the end of file

* refactored code

* which mysql logc changed

* exception message

* newline at end of file

* reverting picklist to simple string

* read me file updated

* mysql task deployment

* Sql file

* L0 test case

* Mysql L0 test completed

* after finally logic

* Review incorporated

* after review incoprated

* review incorporated

* ICon

* proper Identation

* third party notice

* THird party notice

* Removing mysql demands

* telemtry for additional argument

* review incorporated

* review incorporated

* review incorporated

* Review during bugbash

* deleted file

* File again added to rename file as git missed rename changes

* after upgraded npm version

* reverting package json integrity hash changes

* Revert "reverting package json integrity hash changes"

This reverts commit 19265a0.

* Imsataller for mysql

* after addition of mysql path finding proper error

* error msg changed for client not found exception

* Added mysql task in make options for build
  • Loading branch information
RoshanKumarMicrosoft authored Feb 26, 2018
1 parent 9d43978 commit 7a7c194
Show file tree
Hide file tree
Showing 47 changed files with 6,980 additions and 4 deletions.
95 changes: 95 additions & 0 deletions Tasks/AzureMysqlDeployment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Azure Database for Mysql Deployment


### Overview:

The task is used to deploy for deploying to Azure Database for Mysql – Azure’s Mysql DB as a service. There are two ways to deploy, either using a script file or writing the script in our inline editor.


### Contact Information

Please report a problem at [Developer Community Forum](https://developercommunity.visualstudio.com/spaces/21/index.html) if you are facing problems in making this task work. Also, share feedback about the task, and the new features that you would like to see in it.


### Pre-requisites for the task
The following pre-requisites need to be setup for the task to work properly.


##### Azure Subscription

To deploy to Azure Database for Mysql, an Azure subscription has to be linked to Team Foundation Server or to Visual Studio Team Services using the Services tab in the Account Administration section. Add the Azure subscription to use in the Build or Release Management definition by opening the Account Administration screen (gear icon on the top-right of the screen) and then click on the Services Tab.
Use 'Azure Resource Manager'([ARM](https://azure.microsoft.com/en-in/documentation/articles/resource-group-overview/)) endpoint type; for more details follow the steps listed in the link [here](https://go.microsoft.com/fwlink/?LinkID=623000&clcid=0x409).



##### Azure Database for Mysql resource
This tasks expects that the Azure resource for [Azure Database for Mysql](https://docs.microsoft.com/en-us/azure/mysql/overview) is already available in the [Azure portal](https://ms.portal.azure.com/?r=1#create/Microsoft.SQLDatabase.0.5.7-preview). The task can create a new database along with other Mysql commands but doesn't create the server.


### Parameters of the task:
The parameters of the task are described in details, including examples, to show how to input the parameters. The parameters listed with a \* are required parameters for the task:


- **Display name\*:** Provide a name to identify the task among others in your pipeline.


- **Azure subscription\*:** Select the Azure Subscription to connect to the portal where the Azure resource is present.


**DB Details**


- **Host name\*:** Server name of “Azure DB for Mysql”.Example: fabrikam.mysql.database.azure.com. When you connect using Mysql Workbench, this is the same value that is used for "Hostname" in "Parameters".

- **Database name:** The name of database, if you already have one, on which the below script is needed to be run, else the script itself can be used to create the database.

- **Server admin login\*:** Azure Database for MySQL server supports native MySQL authentication. You can connect and authenticate to a server with the server's admin login. Example: bbo1@fabrikam.
When you connect using Mysql Workbench, this is the same value that is used for "Username" in "Parameters".


- **Password\*:** Administrator password for Azure DB for Mysql. In case you don’t recall the password you can change the password from [Azure portal](https://docs.microsoft.com/en-us/azure/mysql/howto-create-manage-server-portal).



**Deployment Package**


- **Type\*:** Select one of the options between Script File & Inline Script.


**Script file:** Use this option if you have a text file that has the necessary SQL statements to be executed on server.


- **Script path\*:** Full path of the script file on the automation agent or on a UNC path accessible to the automation agent like, \\BudgetIT\DeployBuilds\script.sql. Also, predefined [system variables](https://msdn.microsoft.com/Library/vs/alm/Build/scripts/variables) like, $(agent.releaseDirectory) can also be used here.


- **Additional MySQL options:** Additional options supported by mysql simple SQL shell. These options will be applied when executing the given file on the Azure DB for Mysql.
Example: You can change to default tab separated output format to HTML or even XML format. Or if you have problems due to insufficient memory for large result sets, use the --quick option.


**Inline script:** Use this option for running the Inline Script against the server.


- **Inline script\*:** Enter the actuall Script to be run.


- **Additional MySQL options:** Additional options supported by mysql simple SQL shell. These options will be applied when executing the given file on the Azure DB for Mysql.
Example: You can change to default tab separated output format to HTML or even XML format. Or if you have problems due to insufficient memory for large result sets, use the --quick option.



**Firewall**


- **Specify firewall rules using\*** : For successful execution of the task, we need to enable administrators to access the Azure Database for MySQL Server from the IP Address of the automation agent.
By selecting auto-detect you can automatically add firewall exception for range of possible IP Address of automation agent
or else you can specify the range explicitly.


- **Start IP address\*:** The starting IP Address of the automation agent machine pool like 196.21.30.50.


- **End IP address\*:** The ending IP Address of the automation agent machine pool like 196.21.30.65.


- **Delete rule after task ends\*:** If selected, the added exception for IP addresses of the automation agent will be removed for corresponding Azure Database for MySQL.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"loc.friendlyName": "Azure Database for Mysql Deployment",
"loc.helpMarkDown": "[More Information](https://aka.ms/mysqlazuredeployreadme)",
"loc.description": "This is an early preview. Run your scripts and make changes to your Azure DB for Mysql​.",
"loc.instanceNameFormat": "Execute Azure MySQL : $(TaskNameSelector)",
"loc.group.displayName.target": "DB Details",
"loc.group.displayName.taskDetails": "Deployment Package",
"loc.group.displayName.firewall": "Firewall",
"loc.input.label.ConnectedServiceName": "Azure Subscription",
"loc.input.help.ConnectedServiceName": "This is needed to connect to your Azure account.<br>To configure new service connection, select the Azure subscription from the list and click 'Authorize'.<br>If your subscription is not listed or if you want to use an existing Service Principal, you can setup an Azure service connection using 'Add' or 'Manage' button.",
"loc.input.label.ServerName": "Host Name",
"loc.input.help.ServerName": "Server name of 'Azure DB for Mysql'.Example: fabrikam.mysql.database.azure.com. When you connect using Mysql Workbench, this is the same value that is used for 'Hostname' in 'Parameters'",
"loc.input.label.DatabaseName": "Database Name",
"loc.input.help.DatabaseName": "The name of database, if you already have one, on which the below script is needed to be run, else the script itself can be used to create the database.",
"loc.input.label.SqlUsername": "Server Admin Login",
"loc.input.help.SqlUsername": "Azure Database for MySQL server supports native MySQL authentication. You can connect and authenticate to a server with the server's admin login. Example: bbo1@fabrikam. When you connect using Mysql Workbench, this is the same value that is used for 'Username' in 'Parameters'.",
"loc.input.label.SqlPassword": "Password",
"loc.input.help.SqlPassword": "Administrator password for Azure DB for Mysql. In case you don’t recall the password you can change the password from [Azure portal](https://docs.microsoft.com/en-us/azure/mysql/howto-create-manage-server-portal).<br>It can be variable defined in the definition. Example : $(password).<br>Also, you may mark the variable type as 'secret' to secure it.",
"loc.input.label.TaskNameSelector": "Type",
"loc.input.help.TaskNameSelector": "Select one of the options between Script File & Inline Script.",
"loc.input.label.SqlFile": "MySQL Script",
"loc.input.help.SqlFile": "Full path of the script file on the automation agent or on a UNC path accessible to the automation agent like, \\\\\\\\BudgetIT\\DeployBuilds\\script.sql. Also, predefined system variables like, $(agent.releaseDirectory) can also be used here. A file containing SQL statements can be used here.​",
"loc.input.label.SqlInline": "Inline MySQL Script",
"loc.input.help.SqlInline": "Enter the MySQL script to execute on the Database selected above.",
"loc.input.label.SqlAdditionalArguments": "Additional Mysql Arguments",
"loc.input.help.SqlAdditionalArguments": "Additional options supported by mysql simple SQL shell. These options will be applied when executing the given file on the Azure DB for Mysql.​<br>Example: You can change to default tab separated output format to HTML or even XML format. Or if you have problems due to insufficient memory for large result sets, use the --quick option.​",
"loc.input.label.IpDetectionMethod": "Specify Firewall Rules Using",
"loc.input.help.IpDetectionMethod": "For successful execution of the task, we need to enable administrators to access the Azure Database for MySQL Server from the IP Address of the automation agent.<br>By selecting auto-detect you can automatically add firewall exception for range of possible IP Address of automation agent ​or else you can specify the range explicitly.",
"loc.input.label.StartIpAddress": "Start IP Address",
"loc.input.help.StartIpAddress": "The starting IP Address of the automation agent machine pool like 196.21.30.50 .",
"loc.input.label.EndIpAddress": "End IP Address",
"loc.input.help.EndIpAddress": "The ending IP Address of the automation agent machine pool like 196.21.30.65 .",
"loc.input.label.DeleteFirewallRule": "Delete Rule After Task Ends",
"loc.input.help.DeleteFirewallRule": "If selected, the added exception for IP addresses of the automation agent will be removed for corresponding Azure Database for MySQL.",
"loc.messages.ARGD_ConstructorFailed": "Task failed while initializing. Error: %s .",
"loc.messages.FirewallRuleNameCannotBeEmpty": "Firewall rule name cannot be null.",
"loc.messages.FirewallAddressRangeCannotBeEmpty": "Firewall address cannot be null.",
"loc.messages.StartIpAddressCannotBeEmpty": "Start ip address of firewall rule cannot be null.",
"loc.messages.EndIpAddressCannotBeEmpty": "End ip address of firewall rule cannot be null.",
"loc.messages.MysqlServerNameCannotBeEmpty": "Mysql server name cannot be null.",
"loc.messages.MysqlFullyQualifiedServerNameCannotBeEmpty": "Mysql server fully qualified name cannot be null.",
"loc.messages.ResourceGroupCannotBeEmpty": "Resource group name cannot be null.",
"loc.messages.NotAbleToAddFirewallRule": "Getting error in adding firewall rule to mysql server. Error: %s .",
"loc.messages.NotAbleToDeleteFirewallRule": "Getting error in deleting firewall rule to mysql server. Error: %s .",
"loc.messages.AgentIpAddressIsMissingInAddedFirewallRule": "Agent ip address is missing in manually added firewall rule.",
"loc.messages.NotAbleToGetAllServers": "Not able to fetch all mysql server of a subscription. Error: %s .",
"loc.messages.EmptyOrNullServerList": "Mysql server list is empty. Invalid mysql server host name.",
"loc.messages.UnableToFindResourceGroupDueToNullId": "Unable to find resource group due to null id.",
"loc.messages.UnableToFindResourceGroupDueToInvalidId": "Unable to find resource group due to invalid id.",
"loc.messages.NotAbleToGetInstalledLocationOfMysqlFromPath": "Missing mysql client in agent box.",
"loc.messages.UnableToFindMysqlFromRegistryOnMachineError": "Unable to find mysql from registry on machine error.",
"loc.messages.UnableToFindMysqlFromRegistry": "Unable to find mysql from registry. Error: %s .",
"loc.messages.UnableToFindTheLocationOfMysqlFromRegistryOnMachineError": "Unable to find the location of mysql from registry on machine error. Error: %s .",
"loc.messages.AzureMysqlTaskParameterCannotBeEmpty": "Azure mysql task parameter cannot be null.",
"loc.messages.ToolPathCannotBeNull": "Tool path cannot be null.",
"loc.messages.SqlExecutionException": "Sql execution exception. Please Check the sql script. Error: %s .",
"loc.messages.AzureEndpointCannotBeNull": "Invalid subscription name. Azure endpoint can't be null.",
"loc.messages.CallbackCannotBeNull": "callback cannot be null.",
"loc.messages.UnableToCreateDatabaseException": "Unable to create database.",
"loc.messages.WindowMysqlClientMissingError": "Mysql Client is missing in window agent box. Please install it by running mysql client installer 'https://aka.ms/window-mysqlcli-installer' script file in your agent box.",
"loc.messages.LinuxMysqlClientMissingError": "Mysql Client is missing in linux agent box. Please install it by running 'apt-get install mysql-client'."
}
47 changes: 47 additions & 0 deletions Tasks/AzureMysqlDeployment/Tests/FirewallOperationTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import tl = require('vsts-task-lib');
import tmrm = require('vsts-task-lib/mock-run');
import * as path from 'path';
import { MysqlClient } from '../sql/MysqlClient';
import { FirewallConfiguration } from '../models/FirewallConfiguration';

export class FirewallOperationTests {

public static startFirewallOperationL0Tests(){
let tp = path.join(__dirname, 'FirewallOperationsL0Tests.js');
let tr : tmrm.TaskMockRunner = new tmrm.TaskMockRunner(tp);
process.env["RELEASE_RELEASEID"] = "MOCK_RELEASE_ID";
process.env["BUILD_BUILDID"] ="MOCK_BUILD_ID";
tr.setInput('IpDetectionMethod', 'IPAddressRange')
tr.setInput('IpDetectionMethod', 'IPAddressRange');
tr.setInput('ServerName', 'MOCK_SERVER_NAME');
tr.setInput('StartIpAddress', '0.0.0.0');
tr.setInput("EndIpAddress", "2 55.255.255.255");
tr.setInput("IpDetectionMethod", "IPAddressRange");
tr.setInput("ConnectedServiceName", "DEMO_CONNECTED_SERVICE_NAME");
tr.setInput("SqlUsername", "DEMO_SQL_USERNAME");
tr.setInput("SqlPassword","DEMO_SQL_PASSWORD");
tr.setInput("TaskNameSelector", "SqlFile");
Date.now = function (): number {
return 12345;
}
tr.registerMock("../sql/MysqlClient", {
MysqlClient: function(A,B){
return {
getFirewallConfiguration : function() {
let firewallConfiguration: FirewallConfiguration = new FirewallConfiguration(true);
return firewallConfiguration;
},
executeSqlCommand : function(){
return 0;
}
}
}
});

tr.run();
}


}

FirewallOperationTests.startFirewallOperationL0Tests();
50 changes: 50 additions & 0 deletions Tasks/AzureMysqlDeployment/Tests/FirewallOperationsL0Tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { getMockEndpoint, nock, getMockFirewallRules } from './mock_utils';
import * as querystring from 'querystring';
import tl = require('vsts-task-lib');
import { FirewallOperations } from '../operations/FirewallOperations';
import { FirewallRule, FirewallAddressRange } from '../models/Firewall';
import { AzureMysqlTaskParameter } from '../models/AzureMysqlTaskParameter';
import { MysqlClient } from '../sql/MysqlClient';
import { ISqlClient } from '../sql/ISqlClient';
import { MysqlServer } from '../models/MysqlServer';
var endpoint = getMockEndpoint();
getMockFirewallRules();

export class FirewallOperationsL0Tests {

public static firewallOperations: FirewallOperations = new FirewallOperations(endpoint.applicationTokenCredentials, endpoint.subscriptionID);
public static firewallRule: FirewallRule = new FirewallRule("MOCK_FIREWALL_RULE_NAME", new FirewallAddressRange("0.0.0.0", "255.255.255.255"));

public static async testFirewallOperations() {
await FirewallOperationsL0Tests.addFirewallRuleTest();
await FirewallOperationsL0Tests.deleteFirewallRuleTest();
}

public static async addFirewallRuleTest(){
try{
const azureMysqlTaskParameter: AzureMysqlTaskParameter = new AzureMysqlTaskParameter();
const sqlClient: ISqlClient = new MysqlClient(azureMysqlTaskParameter, "MOCK_SERVER_NAME.test-vm1.onebox.xdb.mscds.com", "MOCK_MYSQL_CLIENT_PATH");
const mysqlServer: MysqlServer = new MysqlServer("MOCK_SERVER_NAME", "MOCK_SERVER_NAME.test-vm1.onebox.xdb.mscds.com", "MOCK_RESOURCE_GROUP_NAME");
const response = await FirewallOperationsL0Tests.firewallOperations.invokeFirewallOperations(azureMysqlTaskParameter, sqlClient, mysqlServer);
if(response){
tl.setResult(tl.TaskResult.Succeeded, 'FirewallOperationsL0Tests.addFirewallRuleTest should have succeeded.');
}else{
tl.setResult(tl.TaskResult.Failed, 'FirewallOperationsL0Tests.addFirewallRuleTest should have succeeded but failed.');
}
}catch(error){
tl.setResult(tl.TaskResult.Failed, 'FirewallOperationsL0Tests.addFirewallRuleTest should have succeeded but failed.');
}
}

public static async deleteFirewallRuleTest(){
try{
await FirewallOperationsL0Tests.firewallOperations.deleteFirewallRule("MOCK_SERVER_NAME", "MOCK_RESOURCE_GROUP_NAME");
tl.setResult(tl.TaskResult.Succeeded, 'FirewallOperationsL0Tests.deleteFirewallRuleTest should have succeeded.');
}catch(error){
tl.setResult(tl.TaskResult.Failed, 'FirewallOperationsL0Tests.deleteFirewallRuleTest should have succeeded but failed.');
}
}

}

FirewallOperationsL0Tests.testFirewallOperations();
Loading

0 comments on commit 7a7c194

Please sign in to comment.