8000 adding ssh support for both linux and windows by jackyalbo · Pull Request #3 · CatalystCode/pkgcloud · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 86 additions & 59 deletions lib/pkgcloud/azure-v2/compute/client/servers.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ function getVersion(callback) {
*/
function getLimits(callback) {
return errs.handle(
errs.create({ message: 'Azure\'s API is not rate limited' }),
errs.create({
message: 'Azure\'s API is not rate limited'
}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General remark - I guess you are "beautifying" the code - but this should be done separarately from major changes since I can't tell what are the real changes and what are "white spaces"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is beautify - sorry about that, but as i said the real changes are very small. I will disable it for future use on this project

callback
);
}
Expand All @@ -48,9 +50,9 @@ function getServers(callback) {

var client = new ComputeManagementClient(self.azure.credentials, self.config.subscriptionId);
client.virtualMachines.list(self.config.resourceGroup, function (err, results) {
return err
? callback(err)
: callback(null, results.map(function (res) {
return err ?
callback(err) :
callback(null, results.map(function (res) {
return new self.models.Server(self, res);
}));
});
Expand All @@ -63,7 +65,7 @@ function getServers(callback) {
* @param {Function} callback cb(err, serverId).
*/
function getServer(server, callback) {
var self = this;
var self = this;
var serverId = server instanceof self.models.Server ? server.name : server;

self.login(function (err) {
Expand All @@ -73,37 +75,39 @@ function getServer(server, callback) {
}

var client = new ComputeManagementClient(self.azure.credentials, self.config.subscriptionId);

// This will ensure returning of instances running status
var options = { expand: 'instanceView' };
var options = {
expand: 'instanceView'
};
client.virtualMachines.get(self.config.resourceGroup, serverId, options, function (err, result) {

if (err) {
return callback(err);
}

// Get public dns url
if (!result.networkProfile ||
!result.networkProfile.networkInterfaces ||
!result.networkProfile.networkInterfaces.length) {
if (!result.networkProfile ||
!result.networkProfile.networkInterfaces ||
!result.networkProfile.networkInterfaces.length) {
return callback(null, new self.models.Server(self, result));
}

var networkInterfaceId = result.networkProfile.networkInterfaces[0].id;
var resourceClient = new resourceManagement.ResourceManagementClient(self.azure.credentials, self.config.subscriptionId);

resourceClient.resources.getById(networkInterfaceId, constants.DEFAULT_API_VERSION, function (err, networkInterface) {

if (err) {
return callback(err);
}

if (!networkInterface.properties.ipConfigurations ||
!networkInterface.properties.ipConfigurations.length ||
!networkInterface.properties.ipConfigurations[0] ||
!networkInterface.properties.ipConfigurations[0].properties ||
!networkInterface.properties.ipConfigurations[0].properties.publicIPAddress ||
!networkInterface.properties.ipConfigurations[0].properties.publicIPAddress.id) {
!networkInterface.properties.ipConfigurations.length ||
!networkInterface.properties.ipConfigurations[0] ||
!networkInterface.properties.ipConfigurations[0].properties ||
!networkInterface.properties.ipConfigurations[0].properties.publicIPAddress ||
!networkInterface.properties.ipConfigurations[0].properties.publicIPAddress.id) {
return callback(null, new self.models.Server(self, result));
}

Expand Down Expand Up @@ -143,21 +147,27 @@ function createServer(options, callback) {

if (!options.name || !options.username || !options.password) {
return errs.handle(
errs.create({ message: 'Please provide a name for the vm, as well as the username and password for login' }),
errs.create({
message: 'Please provide a name for the vm, as well as the username and password for login'
}),
callback
);
}

if (!options.flavor) {
return errs.handle(
errs.create({ message: 'When creating an azure server a flavor or an image need to be supplied' }),
errs.create({
message: 'When creating an azure server a flavor or an image need to be supplied'
}),
callback
);
}

var adjustVMTemplate = function (template) {

var vmIndex = _.findIndex(template.resources, { 'type': 'Microsoft.Compute/virtualMachines' });
var vmIndex = _.findIndex(template.resources, {
'type': 'Microsoft.Compute/virtualMachines'
});

// Adding additional data disks
if (options.storageDataDiskNames && options.storageDataDiskNames.length) {
Expand All @@ -174,11 +184,11 @@ function createServer(options, callback) {
});
}

// If this is a windows machine, add an extension that enables remote connection via WinRM
// If this is a windows machine, add an extension that enables ssh connection via Win32-OpenSSH
if (options.osType === 'Windows') {
template.resources[vmIndex].resources = [{
'type': 'Microsoft.Compute/virtualMachines/extensions',
'name': '[concat(variables(\'vmName\'),\'/WinRMCustomScriptExtension\')]',
'name': '[concat(variables(\'vmName\'),\'/Win32sshExtension\')]',
'apiVersion': constants.DEFAULT_API_VERSION,
'location': '[resourceGroup().location]',
'dependsOn': [
Expand All @@ -187,15 +197,30 @@ function createServer(options, callback) {
'properties': {
'publisher': 'Microsoft.Compute',
'type': 'CustomScriptExtension',
'typeHandlerVersion': '1.4',
'typeHandlerVersion': '1.8',
'settings': {
'fileUris': [
'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vm-winrm-windows/ConfigureWinRM.ps1',
'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vm-winrm-windows/makecert.exe',
'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vm-winrm-windows/winrmconf.cmd'
],
'commandToExecute': '[concat(\'powershell -ExecutionPolicy Unrestricted -file ConfigureWinRM.ps1 \',variables(\'hostDNSNameScriptArgument\'))]'
}
'fileUris': ["https://raw.githubusercontent.com/CatalystCode/pkgcloud/master/lib/pkgcloud/azure-v2/scripts/ssh.ps1"],
'commandToExecute': `powershell -File ssh.ps1 ${hostname}\\${options.username} ${options.password}`
},
}
}];
} else { // linux - make sure the new user is in sudoers - so he can sudo with no password
template.resources[vmIndex].resources = [{
'type': 'Microsoft.Compute/virtualMachines/extensions',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you also add a linux extension? from what I remember ssh works by default on Linux machine

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does work, but in none ubuntu linux by default the azure user is not a passwordless sudoer, it has to enter his password before sudoing - so this patch fixes that.

'name': '[concat(variables(\'vmName\'),\'/LinuxSudoExtension\')]',
'apiVersion': constants.DEFAULT_API_VERSION,
'location': '[resourceGroup().location]',
'dependsOn': [
'[concat(\'Microsoft.Compute/virtualMachines/\', variables(\'vmName\'))]'
],
'properties': {
'publisher': 'Microsoft.Compute',
'type': 'CustomScriptForLinux',
'typeHandlerVersion': '1.5',
'settings': {
'fileUris': ["https://raw.githubusercontent.com/CatalystCode/pkgcloud/master/lib/pkgcloud/azure-v2/scripts/sudo.sh"],
'commandToExecute': 'bash sudo.sh ' + options.username
},
}
}];
}
Expand Down Expand Up @@ -236,7 +261,7 @@ function destroyServer(server, options, callback) {
var serverDetails;
var nicsIds;
var nicsDetails;

var vnets;
var publicIPs;

Expand All @@ -255,7 +280,7 @@ function destroyServer(server, options, callback) {
// Deleting the vm
resourceClient = new resourceManagement.ResourceManagementClient(self.azure.credentials, self.config.subscriptionId);
var client = new ComputeManagementClient(self.azure.credentials, self.config.subscriptionId);
client.virtualMachines.deleteMethod(self.config.resourceGroup, serverId, next);
client.virtualMachines.deleteMethod(self.config.resourceGroup, serverId, next);
}
], function (err) {

Expand All @@ -264,19 +289,19 @@ function destroyServer(server, options, callback) {
}

if (!options.destroyNics &&
!options.destroyPublicIP &&
!options.destroyVnet &&
!options.destroyStorage) {
!options.destroyPublicIP &&
!options.destroyVnet &&
!options.destroyStorage) {
return callback();
}

async.waterfall([
function (next) {
// Deleting the nics
nicsIds = serverDetails &&
serverDetails.azure &&
serverDetails.azure.networkProfile &&
serverDetails.azure.networkProfile.networkInterfaces || [];
nicsIds = serverDetails &&
serverDetails.azure &&
serverDetails.azure.networkProfile &&
serverDetails.azure.networkProfile.networkInterfaces || [];

// Go over all nics, get their details and go on to delete them
async.eachSeries(nicsIds, function (nic, cb) {
Expand Down Expand Up @@ -329,7 +354,7 @@ function destroyServer(server, options, callback) {
// Deleting public ips
async.eachSeries(publicIPs, function (publicIP, cb) {
resourceClient.resources.deleteById(publicIP, constants.MANAGEMENT_API_VERSION, cb);
}, next);
}, next);
},
function (next) {

Expand All @@ -340,20 +365,20 @@ function destroyServer(server, options, callback) {
// Deleting vnets
async.eachSeries(vnets, function (vnet, cb) {
resourceClient.resources.deleteById(vnet, constants.MANAGEMENT_API_VERSION, cb);
}, next);
}, next);
},
function (next) {
// Deleting storage account
if (!options.destroyStorage) {
return next();
}

var storageUri = serverDetails &&
serverDetails.azure &&
serverDetails.azure.storageProfile &&
serverDetails.azure.storageProfile.osDisk &&
serverDetails.azure.storageProfile.osDisk.vhd &&
serverDetails.azure.storageProfile.osDisk.vhd.uri || null;
var storageUri = serverDetails &&
serverDetails.azure &&
serverDetails.azure.storageProfile &&
serverDetails.azure.storageProfile.osDisk &&
serverDetails.azure.storageProfile.osDisk.vhd &&
serverDetails.azure.storageProfile.osDisk.vhd.uri || null;

if (!storageUri || !storageUri.startsWith('https://')) {
return next();
Expand All @@ -364,17 +389,17 @@ function destroyServer(server, options, callback) {

// Presuming the storage account is in the same resource group as the vm
resourceClient.resources.deleteMethod(
self.config.resourceGroup,
'Microsoft.Storage',
'storageAccounts',
storageName,
self.config.resourceGroup,
'Microsoft.Storage',
'storageAccounts',
storageName,
'', '2016-01-01', next);
}
], function (error) {
callback(error, serverDetails);
});
});

}

/**
Expand All @@ -394,9 +419,9 @@ function stopServer(server, callback) {

var client = new ComputeManagementClient(self.azure.credentials, self.config.subscriptionId);
client.virtualMachines.powerOff(self.config.resourceGroup, serverId, function (err) {
return err
? callback(err)
: callback(null, serverId);
return err ?
callback(err) :
callback(null, serverId);
});
});
}
Expand All @@ -418,9 +443,9 @@ function rebootServer(server, callback) {

var client = new ComputeManagementClient(self.azure.credentials, self.config.subscriptionId);
client.virtualMachines.restart(self.config.resourceGroup, serverId, function (err) {
return err
? callback(err)
: callback(null, serverId);
return err ?
callback(err) :
callback(null, serverId);
});
});
}
Expand All @@ -432,7 +457,9 @@ function rebootServer(server, callback) {
*/
function renameServer(server, callback) {
return errs.handle(
errs.create({ message: 'Not supported by Azure.' }),
errs.create({
message: 'Not supported by Azure.'
}),
callback
);
}
Expand All @@ -447,4 +474,4 @@ module.exports = {
stopServer: stopServer,
rebootServer: rebootServer,
renameServer: renameServer
};
};
8 changes: 8 additions & 0 deletions lib/pkgcloud/azure-v2/scripts/ssh.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$username = $args[0]
$password = $args[1]
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword
Enable-PSRemoting -Force
$scriptPath = ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/DarwinJS/ChocoPackages/master/openssh/InstallChoco_and_win32-openssh_with_server.ps1'))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better to add this file to the repo or have a fork of the original repo so there are no surprises if it changes in the original repo

Invoke-Command -ScriptBlock ([scriptblock]::Create($scriptPath)) -Credential $credential -ComputerName localhost
Disable-PSRemoting -Force
4 changes: 4 additions & 0 deletions lib/pkgcloud/azure-v2/scripts/sudo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add this file if it is not used? Did you mean to copy the original from DarwinJS/ChocoPackages?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is used by linux - see the previous comment

# Make sure you use a username that is lowercase.
USERNAME=$1
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
0