Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added secrets section in Kubernetes Task #6611

Merged
merged 3 commits into from
Mar 8, 2018
Merged
Show file tree
Hide file tree
Changes from 2 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
18 changes: 11 additions & 7 deletions Tasks/Kubernetes/Strings/resources.resjson/en-US/resources.resjson
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
"loc.description": "Deploy, configure, update your Kubernetes cluster in Azure Container Service by running kubectl commands.",
"loc.instanceNameFormat": "kubectl $(command)",
"loc.group.displayName.commands": "Commands",
"loc.group.displayName.registry": "Container Registry Details",
"loc.group.displayName.secrets": "Secrets",
"loc.group.displayName.advanced": "Advanced",
"loc.group.displayName.output": "Output",
"loc.input.label.kubernetesServiceEndpoint": "Kubernetes Service Connection",
"loc.input.help.kubernetesServiceEndpoint": "Select a Kubernetes service connection.",
"loc.input.label.namespace": "Namespace",
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed with Atul ,the commands and secrets section use the same namespace field so it would be more readable if the namespace field is moved just below the kubernetes service connection field.

"loc.input.help.namespace": "Name of the namespace to run the command in.",
"loc.input.label.command": "Command",
"loc.input.help.command": "Select a kubectl command.",
"loc.input.label.useConfigurationFile": "Use Configuration files",
Expand All @@ -17,6 +19,10 @@
"loc.input.help.configuration": "Filename, directory, or URL to kubernetes configuration files that will be used with the commands.",
"loc.input.label.arguments": "Arguments",
"loc.input.help.arguments": "Command arguments.",
"loc.input.label.secretType": "Type of secret",
"loc.input.help.secretType": "Select a type of secret",
"loc.input.label.secretArguments": "Arguments",
"loc.input.help.secretArguments": "Secret arguments.",
"loc.input.label.containerRegistryType": "Container Registry type",
"loc.input.help.containerRegistryType": "Select a Container registry type.",
"loc.input.label.dockerRegistryEndpoint": "Docker Registry Connection",
Expand All @@ -26,27 +32,25 @@
"loc.input.label.azureContainerRegistry": "Azure Container Registry",
"loc.input.help.azureContainerRegistry": "Select an Azure Container Registry. Required for commands that need to authenticate with a registry.",
"loc.input.label.secretName": "Secret name",
"loc.input.help.secretName": "Name of the docker-registry secret. You can use this secret name in the Kubernetes YAML configuration file.",
"loc.input.help.secretName": "Name of the secret. You can use this secret name in the Kubernetes YAML configuration file.",
"loc.input.label.forceUpdate": "Force update secret",
"loc.input.help.forceUpdate": "Delete the docker-registry secret if it exists and create a new one with updated values.",
"loc.input.help.forceUpdate": "Delete the secret if it exists and create a new one with updated values.",
"loc.input.label.versionOrLocation": "Kubectl",
"loc.input.label.versionSpec": "Version Spec",
"loc.input.help.versionSpec": "Version Spec of version to get. Examples: 1.7.0, 1.x.0, 4.x.0, 6.10.0, >=6.10.0",
"loc.input.label.checkLatest": "Check for Latest Version",
"loc.input.help.checkLatest": "Always checks online for the latest available version (stable.txt) that satisfies the version spec. This is typically false unless you have a specific scenario to always get latest. This will cause it to incur download costs when potentially not necessary, especially with the hosted build pool.",
"loc.input.label.specifyLocation": "Path to Kubectl",
"loc.input.help.specifyLocation": "Full path to the kubectl.exe",
"loc.input.label.namespace": "Namespace",
"loc.input.help.namespace": "Name of the namespace to run the command in.",
"loc.input.label.cwd": "Working directory",
"loc.input.help.cwd": "Working directory for the Kubectl command.",
"loc.input.label.outputFormat": "Output format",
"loc.input.help.outputFormat": "Output format.",
"loc.input.label.kubectlOutput": "Output variable name",
"loc.input.help.kubectlOutput": "Name of the variable in which output of the command should be saved.",
"loc.messages.DownloadingClient": "Downloading kubernetes client.",
"loc.messages.CreatingSecret": "Executing create docker-registry %s secret.",
"loc.messages.DeleteSecret": "Executing delete docker-registry %s secret",
"loc.messages.CreatingSecret": "Executing create %s secret.",
"loc.messages.DeleteSecret": "Executing delete %s secret",
"loc.messages.DockerRegistryConnectionNotSpecified": "Docker Registry connection details not specified",
"loc.messages.FileNotFoundException": "Can not find file at location: %s",
"loc.messages.DownloadingKubeCtlFromUrl": "Downloading Kubectl from Url: %s",
Expand Down
43 changes: 43 additions & 0 deletions Tasks/Kubernetes/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ describe('Kubernetes Suite', function() {
delete process.env[shared.TestEnvVars.namespace];
delete process.env[shared.TestEnvVars.arguments];
delete process.env[shared.TestEnvVars.useConfigurationFile];
delete process.env[shared.TestEnvVars.secretType];
delete process.env[shared.TestEnvVars.secretArguments];
delete process.env[shared.TestEnvVars.secretName];
delete process.env[shared.TestEnvVars.forceUpdate];
delete process.env[shared.TestEnvVars.outputFormat];
Expand Down Expand Up @@ -269,6 +271,47 @@ describe('Kubernetes Suite', function() {
done();
});

it('Runs successfully for kubectl generic secrets with forceUpdate', (done:MochaDone) => {
let tp = path.join(__dirname, 'TestSetup.js');
let tr : ttm.MockTestRunner = new ttm.MockTestRunner(tp);
process.env[shared.TestEnvVars.command] = shared.Commands.get;
process.env[shared.TestEnvVars.arguments] = "pods";
process.env[shared.TestEnvVars.secretType] = "generic";
process.env[shared.TestEnvVars.secretArguments] = "--from-literal=key1=value1 --from-literal=key2=value2";
process.env[shared.TestEnvVars.secretName] = "my-secret";
tr.run();

assert(tr.invokedToolCount == 2, 'should have invoked tool one times. actual: ' + tr.invokedToolCount);
assert(tr.stderr.length == 0 || tr.errorIssues.length, 'should not have written to stderr');
assert(tr.succeeded, 'task should have succeeded');
assert(tr.stdout.indexOf(`DeleteSecret my-secret`) != -1, "kubectl delete should run");
assert(tr.stdout.indexOf(`[command]kubectl --kubeconfig ${shared.formatPath("newUserDir/config")} create secret generic my-secret --from-literal=key1=value1 --from-literal=key2=value2`) != -1, "kubectl create should run");
assert(tr.stdout.indexOf(`[command]kubectl --kubeconfig ${shared.formatPath("newUserDir/config")} get pods`) != -1, "kubectl get should run");
console.log(tr.stderr);
done();
});

it('Runs successfully for kubectl generic secrets without forceUpdate', (done:MochaDone) => {
let tp = path.join(__dirname, 'TestSetup.js');
let tr : ttm.MockTestRunner = new ttm.MockTestRunner(tp);
process.env[shared.TestEnvVars.command] = shared.Commands.get;
process.env[shared.TestEnvVars.arguments] = "pods";
process.env[shared.TestEnvVars.secretType] = "generic";
process.env[shared.TestEnvVars.secretArguments] = "--from-literal=key1=value1 --from-literal=key2=value2";
process.env[shared.TestEnvVars.secretName] = "my-secret";
process.env[shared.TestEnvVars.forceUpdate] = "false";
tr.run();

assert(tr.invokedToolCount == 2, 'should have invoked tool one times. actual: ' + tr.invokedToolCount);
assert(tr.stderr.length == 0 || tr.errorIssues.length, 'should not have written to stderr');
assert(tr.succeeded, 'task should have succeeded');
assert(tr.stdout.indexOf(`DeleteSecret my-secret`) == -1, "kubectl delete should not run");
assert(tr.stdout.indexOf(`[command]kubectl --kubeconfig ${shared.formatPath("newUserDir/config")} create secret generic my-secret --from-literal=key1=value1 --from-literal=key2=value2`) != -1, "kubectl create should run");
assert(tr.stdout.indexOf(`[command]kubectl --kubeconfig ${shared.formatPath("newUserDir/config")} get pods`) != -1, "kubectl get should run");
console.log(tr.stderr);
done();
});

it('Runs successfully for kubectl get and print the output in a particular format', (done:MochaDone) => {
let tp = path.join(__dirname, 'TestSetup.js');
let tr : ttm.MockTestRunner = new ttm.MockTestRunner(tp);
Expand Down
5 changes: 5 additions & 0 deletions Tasks/Kubernetes/Tests/TestSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ tr.setInput('useConfigurationFile', process.env[shared.TestEnvVars.useConfigurat
tr.setInput('configuration', ConfigurationFilePath);
tr.setInput('arguments', process.env[shared.TestEnvVars.arguments] || '');
tr.setInput('namespace', process.env[shared.TestEnvVars.namespace] || '');
tr.setInput('secretType', process.env[shared.TestEnvVars.secretType] || 'dockerRegistry');
tr.setInput('secretArguments', process.env[shared.TestEnvVars.secretArguments] || '');
tr.setInput('secretName', process.env[shared.TestEnvVars.secretName] || '');
tr.setInput('forceUpdate', process.env[shared.TestEnvVars.forceUpdate] || "true");
tr.setInput('versionOrLocation', process.env[shared.TestEnvVars.versionOrLocation] || 'version');
Expand Down Expand Up @@ -98,6 +100,9 @@ a.exec[`kubectl --kubeconfig ${KubconfigFile} create secret docker-registry my-s
a.exec[`kubectl --kubeconfig ${KubconfigFile} create secret docker-registry my-secret --docker-server=https://index.docker.io/v1/ --docker-username=test --docker-password=regpassword [email protected]`] = {
"code": 0
};
a.exec[`kubectl --kubeconfig ${KubconfigFile} create secret generic my-secret --from-literal=key1=value1 --from-literal=key2=value2`] = {
"code": 0
};
a.exec[`kubectl --kubeconfig ${KubconfigFile} get secrets my-secret -o yaml`] = {
"code": 0,
"stdout": "successfully got secret my-secret and printed it in the specified format"
Expand Down
2 changes: 2 additions & 0 deletions Tasks/Kubernetes/Tests/TestShared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export let TestEnvVars = {
configuration: "__configuration__",
arguments: "__arguments__",
namespace: "__namespace__",
secretType: "__secretType__",
secretArguments: "__secretArguments__",
secretName: "__secretName__",
forceUpdate: "__forceUpdate__",
versionOrLocation: "__versionOrLocation__",
Expand Down
4 changes: 2 additions & 2 deletions Tasks/Kubernetes/src/kubernetes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import path = require('path');

import ClusterConnection from "./clusterconnection";
import * as kubectl from "./kubernetescommand";
import * as kubectlRegistrySecret from "./kubernetesregistrysecret";
import * as kubectlSecret from "./kubernetessecret";

import AuthenticationTokenProvider from "docker-common/registryauthenticationprovider/authenticationtokenprovider"
import ACRAuthenticationTokenProvider from "docker-common/registryauthenticationprovider/acrauthenticationtokenprovider"
Expand Down Expand Up @@ -42,7 +42,7 @@ function run(clusterConnection: ClusterConnection, registryAuthenticationToken:
var secretName = tl.getInput("secretName", false);

if(secretName) {
kubectlRegistrySecret.run(clusterConnection, registryAuthenticationToken, secretName).fin(function cleanup(){
kubectlSecret.run(clusterConnection, registryAuthenticationToken, secretName).fin(function cleanup(){
clusterConnection.close();
}).then(function success() {
executeKubectlCommand(clusterConnection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,32 @@ import ClusterConnection from "./clusterconnection";
import AuthenticationToken from "docker-common/registryauthenticationprovider/registryauthenticationtoken"

export function run(connection: ClusterConnection, authenticationToken: AuthenticationToken, secret: string): any {

if(tl.getBoolInput("forceUpdate") == true) {
return deleteSecret(connection, secret).fin(() =>{
return createSecret(connection, authenticationToken, secret);
});
} else {
return createSecret(connection, authenticationToken, secret);
}
}

function createSecret(connection: ClusterConnection, authenticationToken: AuthenticationToken, secret: string): any {
var typeOfSecret = tl.getInput("secretType", true);
if (typeOfSecret === "dockerRegistry")
{
return createDockerRegistrySecret(connection, authenticationToken, secret);
}
else if (typeOfSecret === "generic")
{
return createGenericSecret(connection, secret);
}
}

function deleteSecret(connection: ClusterConnection, secret: string): any {
tl.debug(tl.loc('DeleteSecret', secret));
var command = connection.createCommand();
command.arg(getNameSpace());
Copy link
Contributor

Choose a reason for hiding this comment

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

why this change?

command.arg("delete");
command.arg("secret");
command.arg(secret);
Expand All @@ -33,12 +46,13 @@ function deleteSecret(connection: ClusterConnection, secret: string): any {
return connection.execCommand(command, executionOption);
}

function createSecret(connection: ClusterConnection, authenticationToken: AuthenticationToken, secret: string): any {
function createDockerRegistrySecret(connection: ClusterConnection, authenticationToken: AuthenticationToken, secret: string): any {

if(authenticationToken)
{
tl.debug(tl.loc('CreatingSecret', secret));
var command = connection.createCommand();
command.arg(getNameSpace());
Copy link
Contributor

Choose a reason for hiding this comment

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

why this change?

command.arg("create")
command.arg("secret");
command.arg("docker-registry");
Expand All @@ -47,6 +61,7 @@ function createSecret(connection: ClusterConnection, authenticationToken: Authen
command.arg("--docker-username="+ authenticationToken.getUsername());
command.arg("--docker-password="+ authenticationToken.getPassword());
command.arg("--docker-email="+ authenticationToken.getEmail());

return connection.execCommand(command);
}
else
Expand All @@ -55,4 +70,33 @@ function createSecret(connection: ClusterConnection, authenticationToken: Authen
throw new Error(tl.loc("DockerRegistryConnectionNotSpecified"));
}

}

function createGenericSecret(connection: ClusterConnection, secret: string): any {

tl.debug(tl.loc('CreatingSecret', secret));
var command = connection.createCommand();
command.arg(getNameSpace());
command.arg("create")
command.arg("secret");
command.arg("generic");
command.arg(secret);
var secretArguments = tl.getInput("secretArguments", false);
if (secretArguments)
{
command.line(secretArguments);
}

return connection.execCommand(command);
}

function getNameSpace(): string[] {
var args: string[] =[];
var namespace = tl.getInput("namespace", false);
if(namespace) {
args[0] = "-n";
args[1] = namespace;
}

return args;
}
Loading