Merge branch 'master' into integration_test_fix
This commit is contained in:
Коммит
9550f338fa
|
@ -21,10 +21,7 @@ PCS_CACHE="/tmp/azure/iotpcs/.cache"
|
|||
|
||||
compile() {
|
||||
check_dependency_dotnet
|
||||
|
||||
cd $APP_HOME
|
||||
./scripts/env-vars-check
|
||||
|
||||
|
||||
header "Downloading dependencies..."
|
||||
dotnet restore
|
||||
|
||||
|
@ -37,10 +34,13 @@ run_tests() {
|
|||
|
||||
cd $APP_HOME
|
||||
header "Running tests..."
|
||||
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test')
|
||||
PROJECTS=$(dotnet sln asa-manager.sln list | grep '\.Test')
|
||||
|
||||
for PROJ in $PROJECTS; do
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
PROJ=${PROJ//\\/\/}
|
||||
PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -34,10 +34,13 @@ run_tests() {
|
|||
|
||||
cd $APP_HOME
|
||||
header "Running tests..."
|
||||
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test')
|
||||
PROJECTS=$(dotnet sln auth.sln list | grep '\.Test')
|
||||
|
||||
for PROJ in $PROJECTS; do
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
PROJ=${PROJ//\\/\/}
|
||||
PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@ namespace WebService.Test.Controllers
|
|||
IFormFile file = null;
|
||||
if (isValidFileProvided)
|
||||
{
|
||||
file = this.CreateSampleFile(filename);
|
||||
bool isEdgePackage = (type == "EdgeManifest") ? true : false;
|
||||
file = this.CreateSampleFile(filename, isEdgePackage);
|
||||
}
|
||||
|
||||
Enum.TryParse(type, out PackageType pckgType);
|
||||
|
@ -195,13 +196,20 @@ namespace WebService.Test.Controllers
|
|||
Times.Once);
|
||||
}
|
||||
|
||||
private FormFile CreateSampleFile(string filename)
|
||||
private FormFile CreateSampleFile(string filename, bool isEdgePackage)
|
||||
{
|
||||
var admPackage = "{\"id\":\"dummy\",\"content\":{\"deviceContent\":{}}}";
|
||||
var edgePackage = "{\"id\":\"dummy\",\"content\":{\"modulesContent\":{}}}";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
stream.WriteByte(100);
|
||||
stream.Flush();
|
||||
var writer = new StreamWriter(stream);
|
||||
var package = isEdgePackage ? edgePackage : admPackage;
|
||||
|
||||
writer.Write(package);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return new FormFile(stream, 0, 1, "file", filename);
|
||||
|
||||
return new FormFile(stream, 0, package.Length, "file", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,13 @@ run_tests() {
|
|||
|
||||
cd $APP_HOME
|
||||
header "Running tests..."
|
||||
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test')
|
||||
PROJECTS=$(dotnet sln config.sln list | grep '\.Test')
|
||||
|
||||
for PROJ in $PROJECTS; do
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
PROJ=${PROJ//\\/\/}
|
||||
PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,22 @@ run_container() {
|
|||
|
||||
echo "Starting Config service ..."
|
||||
docker run -it -p 9005:9005 \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_DEVICESIMULATION_WEBSERVICE_URL \
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_SOLUTION_TYPE \
|
||||
-e PCS_AZUREMAPS_KEY \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AUTH_REQUIRED \
|
||||
-e PCS_CORS_WHITELIST \
|
||||
-e PCS_APPLICATION_SECRET \
|
||||
-e PCS_OFFICE365_CONNECTION_URL \
|
||||
-e PCS_SOLUTION_NAME \
|
||||
-e PCS_SUBSCRIPTION_ID \
|
||||
-e PCS_ARM_ENDPOINT_URL \
|
||||
-e PCS_SEED_TEMPLATE \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -19,14 +19,22 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting Config web service ...
|
||||
docker run -it -p 9005:9005 ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_DEVICESIMULATION_WEBSERVICE_URL ^
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_SOLUTION_TYPE ^
|
||||
-e PCS_AZUREMAPS_KEY ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_AUTH_REQUIRED ^
|
||||
-e PCS_CORS_WHITELIST ^
|
||||
-e PCS_APPLICATION_SECRET ^
|
||||
-e PCS_OFFICE365_CONNECTION_URL ^
|
||||
-e PCS_SOLUTION_NAME ^
|
||||
-e PCS_SUBSCRIPTION_ID ^
|
||||
-e PCS_ARM_ENDPOINT_URL ^
|
||||
-e PCS_SEED_TEMPLATE ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services;
|
||||
|
@ -129,5 +126,25 @@ namespace Services.Test
|
|||
this.logger.Verify(l => l.Error(It.IsAny<string>(), It.IsAny<Func<object>>()), Times.Once);
|
||||
this.logger.Verify(l => l.Warn(It.IsAny<string>(), It.IsAny<Func<object>>()), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
|
||||
public async Task ThrowsOnInvalidInput()
|
||||
{
|
||||
// Arrange
|
||||
var xssString = "<body onload=alert('test1')>";
|
||||
var xssList = new List<string>
|
||||
{
|
||||
"<body onload=alert('test1')>",
|
||||
"<IMG SRC=jAvascript:alert('test2')>"
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.alarms.DeleteAsync(xssString));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.alarms.Delete(xssList));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.alarms.UpdateAsync(xssString, xssString));
|
||||
Assert.Throws<InvalidInputException>(() => this.alarms.GetCountByRule(xssString, DateTimeOffset.MaxValue, DateTimeOffset.MaxValue, xssList.ToArray()));
|
||||
Assert.Throws<InvalidInputException>(() => this.alarms.List(null, null, xssString, 0, 1, xssList.ToArray()));
|
||||
Assert.Throws<InvalidInputException>(() => this.alarms.ListByRule(xssString, DateTimeOffset.MaxValue, DateTimeOffset.MaxValue, xssString, 0, 1, xssList.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,12 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Diagnostics;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Exceptions;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Runtime;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Storage.CosmosDB;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Storage.TimeSeries;
|
||||
using Moq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Services.Test.helpers;
|
||||
|
@ -17,11 +22,23 @@ namespace Services.Test
|
|||
private const int SKIP = 0;
|
||||
private const int LIMIT = 1000;
|
||||
|
||||
private readonly Mock<IMessages> messages;
|
||||
private readonly Mock<IStorageClient> storageClient;
|
||||
private readonly Mock<ITimeSeriesClient> timeSeriesClient;
|
||||
private readonly Mock<ILogger> logger;
|
||||
|
||||
private readonly IMessages messages;
|
||||
|
||||
public MessagesTest()
|
||||
{
|
||||
this.messages = new Mock<IMessages>();
|
||||
var servicesConfig = new ServicesConfig()
|
||||
{
|
||||
MessagesConfig = new StorageConfig("database", "collection"),
|
||||
StorageType = "tsi"
|
||||
};
|
||||
this.storageClient = new Mock<IStorageClient>();
|
||||
this.timeSeriesClient = new Mock<ITimeSeriesClient>();
|
||||
this.logger = new Mock<ILogger>();
|
||||
this.messages = new Messages(servicesConfig, this.storageClient.Object, this.timeSeriesClient.Object, this.logger.Object);
|
||||
}
|
||||
|
||||
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
|
||||
|
@ -29,9 +46,10 @@ namespace Services.Test
|
|||
{
|
||||
// Arrange
|
||||
this.ThereAreNoMessagesInStorage();
|
||||
var devices = new string[] { "device1" };
|
||||
|
||||
// Act
|
||||
var list = await this.messages.Object.ListAsync(null, null, null, SKIP, LIMIT, null);
|
||||
var list = await this.messages.ListAsync(null, null, "asc", SKIP, LIMIT, devices);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(list.Messages);
|
||||
|
@ -43,18 +61,34 @@ namespace Services.Test
|
|||
{
|
||||
// Arrange
|
||||
this.ThereAreSomeMessagesInStorage();
|
||||
var devices = new string[] { "device1" };
|
||||
|
||||
// Act
|
||||
var list = await this.messages.Object.ListAsync(null, null, null, SKIP, LIMIT, null);
|
||||
var list = await this.messages.ListAsync(null, null, "asc", SKIP, LIMIT, devices);
|
||||
|
||||
// Assert
|
||||
Assert.NotEmpty(list.Messages);
|
||||
Assert.NotEmpty(list.Properties);
|
||||
}
|
||||
|
||||
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
|
||||
public async Task ThrowsOnInvalidInput()
|
||||
{
|
||||
// Arrange
|
||||
var xssString = "<body onload=alert('test1')>";
|
||||
var xssList = new List<string>
|
||||
{
|
||||
"<body onload=alert('test1')>",
|
||||
"<IMG SRC=jAvascript:alert('test2')>"
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.messages.ListAsync(null, null, xssString, 0, LIMIT, xssList.ToArray()));
|
||||
}
|
||||
|
||||
private void ThereAreNoMessagesInStorage()
|
||||
{
|
||||
this.messages.Setup(x => x.ListAsync(null, null, null, SKIP, LIMIT, null))
|
||||
this.timeSeriesClient.Setup(x => x.QueryEventsAsync(null, null, It.IsAny<string>(), SKIP, LIMIT, It.IsAny<string[]>()))
|
||||
.ReturnsAsync(new MessageList());
|
||||
}
|
||||
|
||||
|
@ -75,7 +109,7 @@ namespace Services.Test
|
|||
sampleProperties.Add("data.sample_unit");
|
||||
sampleProperties.Add("data.sample_speed");
|
||||
|
||||
this.messages.Setup(x => x.ListAsync(null, null, null, SKIP, LIMIT, null))
|
||||
this.timeSeriesClient.Setup(x => x.QueryEventsAsync(null, null, It.IsAny<string>(), SKIP, LIMIT, It.IsAny<string[]>()))
|
||||
.ReturnsAsync(new MessageList(sampleMessages, sampleProperties));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ using Moq;
|
|||
using Newtonsoft.Json;
|
||||
using Services.Test.helpers;
|
||||
using Xunit;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Services.Test
|
||||
{
|
||||
|
@ -405,6 +404,74 @@ namespace Services.Test
|
|||
this.httpClientMock.Verify(x => x.PostAsync(It.IsAny<HttpRequest>()), Times.Exactly(4));
|
||||
}
|
||||
|
||||
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
|
||||
public async Task ThrowsOnInvalidInput()
|
||||
{
|
||||
// Arrange
|
||||
var xssString = "<body onload=alert('test1')>";
|
||||
var xssList = new List<string>
|
||||
{
|
||||
"<body onload=alert('test1')>",
|
||||
"<IMG SRC=jAvascript:alert('test2')>"
|
||||
};
|
||||
|
||||
var rule = new Rule()
|
||||
{
|
||||
ETag = xssString,
|
||||
Id = xssString,
|
||||
Name = xssString,
|
||||
DateCreated = xssString,
|
||||
DateModified = xssString,
|
||||
Enabled = true,
|
||||
Description = xssString,
|
||||
GroupId = xssString,
|
||||
Severity = SeverityType.Critical,
|
||||
Conditions = new List<Condition>
|
||||
{
|
||||
new Condition()
|
||||
{
|
||||
Field = "sample_conddition",
|
||||
Operator = OperatorType.Equals,
|
||||
Value = "1"
|
||||
}
|
||||
},
|
||||
Actions = new List<IAction>
|
||||
{
|
||||
new EmailAction(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "recipients", new Newtonsoft.Json.Linq.JArray(){ "sampleEmail@gmail.com", "sampleEmail2@gmail.com" } },
|
||||
{ "subject", "Test Email" },
|
||||
{ "notes", "Test Email Notes." }
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.DeleteAsync(xssString));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.DeleteAsync(xssString));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.GetAsync(xssString));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.GetListAsync(xssString, 0, 1, xssString, false));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.GetAlarmCountForListAsync(null, null, xssString, 0, LIMIT, xssList.ToArray()));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.CreateAsync(rule));
|
||||
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.UpsertIfNotDeletedAsync(rule));
|
||||
}
|
||||
|
||||
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
|
||||
public void InputValidationPassesWithValidRule()
|
||||
{
|
||||
// Arrange
|
||||
this.ThereAreSomeRulesInStorage();
|
||||
|
||||
List<Rule> rulesList = this.GetSampleRulesList();
|
||||
|
||||
// Act & Assert
|
||||
foreach (var rule in rulesList)
|
||||
{
|
||||
rule.Validate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThereAreNoRulessInStorage()
|
||||
{
|
||||
this.rulesMock.Setup(x => x.GetListAsync(null, 0, LIMIT, null, false))
|
||||
|
@ -412,6 +479,14 @@ namespace Services.Test
|
|||
}
|
||||
|
||||
private void ThereAreSomeRulesInStorage()
|
||||
{
|
||||
var sampleRules = this.GetSampleRulesList();
|
||||
|
||||
this.rulesMock.Setup(x => x.GetListAsync(null, 0, LIMIT, null, false))
|
||||
.ReturnsAsync(sampleRules);
|
||||
}
|
||||
|
||||
private List<Rule> GetSampleRulesList()
|
||||
{
|
||||
var sampleConditions = new List<Condition>
|
||||
{
|
||||
|
@ -440,7 +515,7 @@ namespace Services.Test
|
|||
{
|
||||
Name = "Sample 1",
|
||||
Enabled = true,
|
||||
Description = "Sample description 1",
|
||||
Description = "Sample description 1 -- Pressure >= 298",
|
||||
GroupId = "Prototyping devices",
|
||||
Severity = SeverityType.Critical,
|
||||
Conditions = sampleConditions,
|
||||
|
@ -455,11 +530,22 @@ namespace Services.Test
|
|||
Severity = SeverityType.Warning,
|
||||
Conditions = sampleConditions,
|
||||
Actions = sampleActions
|
||||
},
|
||||
new Rule()
|
||||
{
|
||||
ETag = "*",
|
||||
Name = "Sample 3",
|
||||
Enabled = true,
|
||||
Calculation = CalculationType.Instant,
|
||||
Description = "Sample description 2.",
|
||||
GroupId = "Chillers",
|
||||
Severity = SeverityType.Warning,
|
||||
Conditions = sampleConditions,
|
||||
Actions = sampleActions
|
||||
}
|
||||
};
|
||||
|
||||
this.rulesMock.Setup(x => x.GetListAsync(null, 0, LIMIT, null, false))
|
||||
.ReturnsAsync(sampleRules);
|
||||
return sampleRules;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
@ -55,8 +52,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public class Alarms : IAlarms
|
||||
{
|
||||
private const string INVALID_CHARACTER = @"[^A-Za-z0-9:;.,_\-]";
|
||||
|
||||
private readonly ILogger log;
|
||||
private readonly IStorageClient storageClient;
|
||||
|
||||
|
@ -90,11 +85,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public Alarm Get(string id)
|
||||
{
|
||||
if (Regex.IsMatch(id, INVALID_CHARACTER))
|
||||
{
|
||||
throw new InvalidInputException("id contains illegal characters.");
|
||||
}
|
||||
|
||||
Document doc = this.GetDocumentById(id);
|
||||
return new Alarm(doc);
|
||||
}
|
||||
|
@ -160,11 +150,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
limit,
|
||||
devices, DEVICE_ID_KEY);
|
||||
|
||||
if (Regex.IsMatch(id, INVALID_CHARACTER))
|
||||
{
|
||||
throw new InvalidInputException("id contains illegal characters.");
|
||||
}
|
||||
|
||||
this.log.Debug("Created Alarm By Rule Query", () => new { sql });
|
||||
|
||||
FeedOptions queryOptions = new FeedOptions();
|
||||
|
@ -220,10 +205,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public async Task<Alarm> UpdateAsync(string id, string status)
|
||||
{
|
||||
if (Regex.IsMatch(id, INVALID_CHARACTER))
|
||||
{
|
||||
throw new InvalidInputException("id contains illegal characters.");
|
||||
}
|
||||
InputValidator.Validate(id);
|
||||
InputValidator.Validate(status);
|
||||
|
||||
Document document = this.GetDocumentById(id);
|
||||
document.SetPropertyValue(STATUS_KEY, status);
|
||||
|
@ -238,10 +221,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
private Document GetDocumentById(string id)
|
||||
{
|
||||
if (Regex.IsMatch(id, INVALID_CHARACTER))
|
||||
{
|
||||
throw new InvalidInputException("id contains illegal characters.");
|
||||
}
|
||||
InputValidator.Validate(id);
|
||||
|
||||
var query = new SqlQuerySpec(
|
||||
"SELECT * FROM c WHERE c.id=@id",
|
||||
|
@ -268,6 +248,11 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public async Task Delete(List<string> ids)
|
||||
{
|
||||
foreach(var id in ids)
|
||||
{
|
||||
InputValidator.Validate(id);
|
||||
}
|
||||
|
||||
Task[] taskList = new Task[ids.Count];
|
||||
for (int i = 0; i < ids.Count; i++)
|
||||
{
|
||||
|
@ -292,6 +277,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
*/
|
||||
public async Task DeleteAsync(string id)
|
||||
{
|
||||
InputValidator.Validate(id);
|
||||
|
||||
int retryCount = 0;
|
||||
while (retryCount < this.maxDeleteRetryCount)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Exceptions;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Helpers
|
||||
{
|
||||
public class InputValidator
|
||||
{
|
||||
private const string INVALID_CHARACTER = @"[^A-Za-z0-9:;.!,_\-* ]";
|
||||
|
||||
// Check illegal characters in input
|
||||
public static void Validate(string input)
|
||||
{
|
||||
if (Regex.IsMatch(input.Trim(), INVALID_CHARACTER))
|
||||
{
|
||||
throw new InvalidInputException($"Input '{input}' contains invalid characters.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Helpers
|
|||
ValidateInput(ref schemaName);
|
||||
ValidateInput(ref fromProperty);
|
||||
ValidateInput(ref toProperty);
|
||||
ValidateInput(ref order);
|
||||
ValidateInput(ref orderProperty);
|
||||
for (int i = 0; i < devices.Length; i++)
|
||||
{
|
||||
ValidateInput(ref devices[i]);
|
||||
}
|
||||
ValidateInput(ref devicesProperty);
|
||||
|
||||
var sqlParameterCollection = new SqlParameterCollection();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
|
@ -68,6 +68,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
int limit,
|
||||
string[] devices)
|
||||
{
|
||||
InputValidator.Validate(order);
|
||||
foreach (var device in devices)
|
||||
{
|
||||
InputValidator.Validate(device);
|
||||
}
|
||||
|
||||
return this.timeSeriesEnabled ?
|
||||
await this.GetListFromTimeSeriesAsync(from, to, order, skip, limit, devices) :
|
||||
this.GetListFromCosmosDb(from, to, order, skip, limit, devices);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Helpers;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models.Actions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
@ -11,6 +12,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models
|
|||
public class Rule : IComparable<Rule>
|
||||
{
|
||||
private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:sszzz";
|
||||
|
||||
// Comes from the StorageAdapter document and not the serialized rule
|
||||
[JsonIgnore]
|
||||
public string ETag { get; set; } = string.Empty;
|
||||
|
@ -41,6 +43,11 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models
|
|||
return DateTimeOffset.Parse(other.DateCreated)
|
||||
.CompareTo(DateTimeOffset.Parse(this.DateCreated));
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
InputValidator.Validate(this.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public enum CalculationType
|
||||
|
|
|
@ -4,7 +4,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Diagnostics;
|
||||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Exceptions;
|
||||
|
@ -49,7 +48,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
public class Rules : IRules
|
||||
{
|
||||
private const string STORAGE_COLLECTION = "rules";
|
||||
private const string INVALID_CHARACTER = @"[^A-Za-z0-9:;.,_\-]";
|
||||
private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:sszzz";
|
||||
|
||||
private readonly IStorageAdapterClient storage;
|
||||
|
@ -91,6 +89,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public async Task DeleteAsync(string id)
|
||||
{
|
||||
InputValidator.Validate(id);
|
||||
|
||||
Rule existing;
|
||||
try
|
||||
{
|
||||
|
@ -125,11 +125,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public async Task<Rule> GetAsync(string id)
|
||||
{
|
||||
if (Regex.IsMatch(id, INVALID_CHARACTER))
|
||||
{
|
||||
this.log.Debug("id contains illegal characters.", () => new { id });
|
||||
throw new InvalidInputException("id contains illegal characters.");
|
||||
}
|
||||
InputValidator.Validate(id);
|
||||
|
||||
var item = await this.storage.GetAsync(STORAGE_COLLECTION, id);
|
||||
var rule = this.Deserialize(item.Data);
|
||||
|
@ -147,6 +143,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
string groupId,
|
||||
bool includeDeleted)
|
||||
{
|
||||
InputValidator.Validate(order);
|
||||
if (!string.IsNullOrEmpty(groupId))
|
||||
{
|
||||
InputValidator.Validate(groupId);
|
||||
}
|
||||
|
||||
var data = await this.storage.GetAllAsync(STORAGE_COLLECTION);
|
||||
var ruleList = new List<Rule>();
|
||||
foreach (var item in data.Items)
|
||||
|
@ -205,6 +207,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
int limit,
|
||||
string[] devices)
|
||||
{
|
||||
InputValidator.Validate(order);
|
||||
foreach (var device in devices)
|
||||
{
|
||||
InputValidator.Validate(device);
|
||||
}
|
||||
|
||||
var alarmCountByRuleList = new List<AlarmCountByRule>();
|
||||
|
||||
// get list of rules
|
||||
|
@ -246,6 +254,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
{
|
||||
throw new InvalidInputException("Rule not provided.");
|
||||
}
|
||||
rule.Validate();
|
||||
|
||||
// Ensure dates are correct
|
||||
rule.DateCreated = DateTimeOffset.UtcNow.ToString(DATE_FORMAT);
|
||||
|
@ -265,6 +274,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
|
|||
|
||||
public async Task<Rule> UpsertIfNotDeletedAsync(Rule rule)
|
||||
{
|
||||
rule.Validate();
|
||||
|
||||
if (rule == null)
|
||||
{
|
||||
throw new InvalidInputException("Rule not provided.");
|
||||
|
|
|
@ -22,9 +22,6 @@ PCS_CACHE="/tmp/azure/iotpcs/.cache"
|
|||
compile() {
|
||||
check_dependency_dotnet
|
||||
|
||||
cd $APP_HOME
|
||||
./scripts/env-vars-check
|
||||
|
||||
header "Downloading dependencies..."
|
||||
dotnet restore
|
||||
|
||||
|
@ -37,10 +34,13 @@ run_tests() {
|
|||
|
||||
cd $APP_HOME
|
||||
header "Running tests..."
|
||||
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test')
|
||||
PROJECTS=$(dotnet sln telemetry.sln list | grep '\.Test')
|
||||
|
||||
for PROJ in $PROJECTS; do
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
PROJ=${PROJ//\\/\/}
|
||||
PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,15 @@ run_container() {
|
|||
|
||||
echo "Starting Telemetry service..."
|
||||
docker run -it -p 9004:9004 \
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_DIAGNOSTICS_WEBSERVICE_URL \
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AUTH_REQUIRED \
|
||||
-e PCS_CORS_WHITELIST \
|
||||
-e PCS_APPLICATION_SECRET \
|
||||
-e PCS_AAD_TENANT \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
|
@ -30,7 +34,7 @@ run_container() {
|
|||
-e PCS_ACTION_EVENTHUB_CONNSTRING \
|
||||
-e PCS_ACTION_EVENTHUB_NAME \
|
||||
-e PCS_LOGICAPP_ENDPOINT_URL \
|
||||
-e PCS_SOLUTION_NAME \
|
||||
-e PCS_SOLUTION_WEBSITE_URL \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,15 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting Telemetry service...
|
||||
docker run -it -p 9004:9004 ^
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_DIAGNOSTICS_WEBSERVICE_URL ^
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_AUTH_REQUIRED ^
|
||||
-e PCS_CORS_WHITELIST ^
|
||||
-e PCS_APPLICATION_SECRET ^
|
||||
-e PCS_AAD_TENANT ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
|
@ -35,7 +39,7 @@ docker run -it -p 9004:9004 ^
|
|||
-e PCS_ACTION_EVENTHUB_CONNSTRING ^
|
||||
-e PCS_ACTION_EVENTHUB_NAME ^
|
||||
-e PCS_LOGICAPP_ENDPOINT_URL ^
|
||||
-e PCS_SOLUTION_NAME ^
|
||||
-e PCS_SOLUTION_WEBSITE_URL ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
CI/CD for Remote Monitoring
|
||||
===
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
@ -22,9 +23,10 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.RecurringTasksAgent
|
|||
|
||||
// When generating the cache, allow some time to finish, at least one minute
|
||||
private const int CACHE_TIMEOUT_SECS = 90;
|
||||
|
||||
|
||||
private readonly IDeviceProperties deviceProperties;
|
||||
private readonly ILogger log;
|
||||
private Timer cacheUpdateTimer;
|
||||
|
||||
public Agent(
|
||||
IDeviceProperties deviceProperties,
|
||||
|
@ -66,7 +68,7 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.RecurringTasksAgent
|
|||
try
|
||||
{
|
||||
this.log.Info("Scheduling a DeviceProperties cache update", () => new { CACHE_UPDATE_SECS });
|
||||
var unused = new Timer(
|
||||
this.cacheUpdateTimer = new Timer(
|
||||
this.UpdateDevicePropertiesCache,
|
||||
null,
|
||||
1000 * CACHE_UPDATE_SECS,
|
||||
|
|
|
@ -20,9 +20,6 @@ PCS_CACHE="/tmp/azure/iotpcs/.cache"
|
|||
compile() {
|
||||
check_dependency_dotnet
|
||||
|
||||
cd $APP_HOME
|
||||
./scripts/env-vars-check
|
||||
|
||||
header "Downloading dependencies..."
|
||||
dotnet restore
|
||||
|
||||
|
@ -35,10 +32,13 @@ run_tests() {
|
|||
|
||||
cd $APP_HOME
|
||||
header "Running tests..."
|
||||
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test')
|
||||
PROJECTS=$(dotnet sln iothub-manager.sln list | grep '\.Test')
|
||||
|
||||
for PROJ in $PROJECTS; do
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
PROJ=${PROJ//\\/\/}
|
||||
PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
|
||||
echo "-- $PROJ"
|
||||
dotnet test --configuration $CONFIGURATION $PROJ
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: asamanager
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "asamanager.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "asamanager.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "asamanager.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "asamanager.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 9024:9024
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "asamanager.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "asamanager.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "asamanager.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,76 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "asamanager.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "asamanager.name" . }}
|
||||
chart: {{ template "asamanager.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "asamanager.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "asamanager.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if not .Values.disableProbes }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "asamanager.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "asamanager.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "asamanager.name" . }}
|
||||
chart: {{ template "asamanager.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: http
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "asamanager.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "asamanager.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "asamanager.name" . }}
|
||||
chart: {{ template "asamanager.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "asamanager.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,75 @@
|
|||
# Default values for asamanager.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: asamanager
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/asa-manager-dotnet
|
||||
tag: testing
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
service:
|
||||
type: ClusterIP
|
||||
externalPort: 80
|
||||
internalPort: 9024
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
#annotations:
|
||||
# kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /asamanager
|
||||
hosts:
|
||||
- DNSNAME
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
secrets:
|
||||
asamanager:
|
||||
PCS_TELEMETRY_DOCUMENTDB_CONNSTRING: PCS_TELEMETRY_DOCUMENTDB_CONNSTRING
|
||||
PCS_TELEMETRY_WEBSERVICE_URL: PCS_TELEMETRY_WEBSERVICE_URL
|
||||
PCS_CONFIG_WEBSERVICE_URL: PCS_CONFIG_WEBSERVICE_URL
|
||||
PCS_IOTHUBMANAGER_WEBSERVICE_URL: PCS_IOTHUBMANAGER_WEBSERVICE_URL
|
||||
PCS_ASA_DATA_AZUREBLOB_ACCOUNT: PCS_ASA_DATA_AZUREBLOB_ACCOUNT
|
||||
PCS_ASA_DATA_AZUREBLOB_KEY: PCS_ASA_DATA_AZUREBLOB_KEY
|
||||
PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX: PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX
|
||||
PCS_EVENTHUB_CONNSTRING: PCS_EVENTHUB_CONNSTRING
|
||||
PCS_EVENTHUB_NAME: PCS_EVENTHUB_NAME
|
||||
PCS_TELEMETRY_STORAGE_TYPE: PCS_TELEMETRY_STORAGE_TYPE
|
||||
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: auth
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "auth.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "auth.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "auth.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "auth.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "auth.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "auth.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "auth.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,76 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "auth.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "auth.name" . }}
|
||||
chart: {{ template "auth.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "auth.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "auth.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if not .Values.disableProbes }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "auth.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "auth.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "auth.name" . }}
|
||||
chart: {{ template "auth.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: http
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "auth.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "auth.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "auth.name" . }}
|
||||
chart: {{ template "auth.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "auth.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,66 @@
|
|||
# Default values for auth.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: auth
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/pcs-auth-dotnet
|
||||
tag: testing
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
service:
|
||||
type: ClusterIP
|
||||
externalPort: 80
|
||||
internalPort: 9001
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
#annotations:
|
||||
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /auth
|
||||
hosts:
|
||||
- DNSNAME
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
secrets:
|
||||
auth:
|
||||
PCS_AUTH_AUDIENCE: PCS_AUTH_AUDIENCE
|
||||
PCS_AUTH_ISSUER: PCS_AUTH_ISSUER
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: config
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "config.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "config.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "config.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "config.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "config.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "config.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "config.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,76 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "config.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "config.name" . }}
|
||||
chart: {{ template "config.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "config.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "config.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if not .Values.disableProbes }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "config.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "config.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "config.name" . }}
|
||||
chart: {{ template "config.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: http
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "config.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "config.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "config.name" . }}
|
||||
chart: {{ template "config.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "config.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,70 @@
|
|||
# Default values for config.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: config
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/pcs-config-dotnet
|
||||
tag: testing
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
service:
|
||||
type: ClusterIP
|
||||
externalPort: 80
|
||||
internalPort: 9005
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
#annotations:
|
||||
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /config
|
||||
hosts:
|
||||
- DNSNAME
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
secrets:
|
||||
config:
|
||||
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||
PCS_DEVICESIMULATION_WEBSERVICE_URL: PCS_DEVICESIMULATION_WEBSERVICE_URL
|
||||
PCS_TELEMETRY_WEBSERVICE_URL: PCS_TELEMETRY_WEBSERVICE_URL
|
||||
PCS_AZUREMAPS_KEY: PCS_AZUREMAPS_KEY
|
||||
PCS_AUTH_WEBSERVICE_URL: PCS_AUTH_WEBSERVICE_URL
|
||||
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
####### helm delete release
|
||||
echo "Config current context"
|
||||
kubectl config current-context
|
||||
|
||||
echo "Deleting services from above context"
|
||||
helm delete storageadapter
|
||||
helm delete telemetry
|
||||
helm delete iothubmanager
|
||||
helm delete simulation
|
||||
helm delete auth
|
||||
helm delete webui
|
||||
helm delete asamanager
|
||||
helm delete config
|
||||
####### helm purgedelete to ensure if above cmds don't work
|
||||
helm del --purge storageadapter
|
||||
helm del --purge telemetry
|
||||
helm del --purge iothubmanager
|
||||
helm del --purge simulation
|
||||
helm del --purge auth
|
||||
helm del --purge webui
|
||||
helm del --purge asamanager
|
||||
helm del --purge config
|
||||
##################### Delete any other resources
|
||||
kubectl delete secret storageadapter-storageadapter
|
||||
exit 0
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
source .env
|
||||
####### Install helm charts
|
||||
install() {
|
||||
# helm install --name storageadapter storageadapter/charts/storageadapter/ --set secrets.storageadapter.PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING=${PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING} --set-string secrets.storageadapter.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||
|
||||
helm install --name telemetry telemetry/charts/devicetelemetry/ --set secrets.devicetelemetry.PCS_TELEMETRY_DOCUMENTDB_CONNSTRING=${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING} --set secrets.devicetelemetry.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set secrets.devicetelemetry.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set secrets.devicetelemetry.PCS_AUTH_WEBSERVICE_URL=${PCS_AUTH_WEBSERVICE_URL} --set secrets.devicetelemetry.PCS_AAD_TENANT=${PCS_AAD_TENANT} --set secrets.devicetelemetry.PCS_AAD_APPID=${PCS_AAD_APPID} --set secrets.devicetelemetry.PCS_AAD_APPSECRET=${PCS_AAD_APPSECRET} --set secrets.devicetelemetry.PCS_TELEMETRY_STORAGE_TYPE=${PCS_TELEMETRY_STORAGE_TYPE} --set secrets.devicetelemetry.PCS_TSI_FQDN=${PCS_TSI_FQDN} --set-string secrets.devicetelemetry.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||
|
||||
helm install --name iothubmanager iothubmanager/charts/iothubmanager/ --set secrets.iothubmanager.PCS_IOTHUB_CONNSTRING=${PCS_IOTHUB_CONNSTRING} --set secrets.iothubmanager.PCS_AUTH_WEBSERVICE_URL=${PCS_AUTH_WEBSERVICE_URL} --set secrets.iothubmanager.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set-string secrets.iothubmanager.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||
|
||||
helm install --name simulation simulation/charts/simulation/ --set secrets.simulation.PCS_IOTHUB_CONNSTRING=${PCS_IOTHUB_CONNSTRING} --set secrets.simulation.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set-string secrets.simulation.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||
|
||||
helm install --name config config/charts/config --set secrets.config.PCS_DEVICESIMULATION_WEBSERVICE_URL=${PCS_DEVICESIMULATION_WEBSERVICE_URL} --set secrets.config.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set secrets.config.PCS_TELEMETRY_WEBSERVICE_URL=${PCS_TELEMETRY_WEBSERVICE_URL} --set secrets.config.PCS_AZUREMAPS_KEY=${PCS_AZUREMAPS_KEY} --set secrets.config.PCS_AUTH_WEBSERVICE_URL=${PCS_AUTH_WEBSERVICE_URL} --set-string secrets.config.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED} --debug
|
||||
|
||||
helm install --name asamanager asamanager/charts/asamanager/ --set secrets.asamanager.PCS_ASA_DATA_AZUREBLOB_ACCOUNT=${PCS_ASA_DATA_AZUREBLOB_ACCOUNT} --set secrets.asamanager.PCS_ASA_DATA_AZUREBLOB_KEY=${PCS_ASA_DATA_AZUREBLOB_KEY} --set secrets.asamanager.PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX=${PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX} --set secrets.asamanager.PCS_EVENTHUB_CONNSTRING=${PCS_EVENTHUB_CONNSTRING} --set secrets.asamanager.PCS_EVENTHUB_NAME=${PCS_EVENTHUB_NAME} --set secrets.asamanager.PCS_TELEMETRY_DOCUMENTDB_CONNSTRING=${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING} --set secrets.asamanager.PCS_TELEMETRY_WEBSERVICE_URL=${PCS_TELEMETRY_WEBSERVICE_URL} --set secrets.asamanager.PCS_CONFIG_WEBSERVICE_URL=${PCS_CONFIG_WEBSERVICE_URL} --set secrets.asamanager.PCS_IOTHUBMANAGER_WEBSERVICE_URL=${PCS_IOTHUBMANAGER_WEBSERVICE_URL} --set secrets.asamanager.PCS_TELEMETRY_STORAGE_TYPE=${PCS_TELEMETRY_STORAGE_TYPE} --set-string secrets.asamanager.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED} --debug
|
||||
|
||||
helm install --name auth auth/charts/auth/ --set secrets.auth.PCS_AUTH_AUDIENCE=${PCS_AUTH_AUDIENCE} --set secrets.auth.PCS_AUTH_ISSUER=${PCS_AUTH_ISSUER}
|
||||
|
||||
helm install --name webui webui/charts/webui/ --set REACT_APP_BASE_SERVICE_URL=${REACT_APP_BASE_SERVICE_URL}
|
||||
|
||||
helm install --name reverse-proxy reverse-proxy/charts/reverse-proxy/
|
||||
}
|
||||
##########################
|
||||
|
||||
upgrade() {
|
||||
helm upgrade --install --force storageadapter storageadapter/ --set secrets.storageadapter.PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING=${PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING} --set-string secrets.storageadapter.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED} --debug
|
||||
}
|
||||
|
||||
|
||||
must_run_once_more(){
|
||||
#### Thisstep is required due to bug in helm https://github.com/helm/helm/issues/1479
|
||||
helm install --name storageadapter storageadapter/ --set secrets.storageadapter.PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING=${PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING} --set-string secrets.storageadapter.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
must_run_once_more
|
||||
|
||||
install
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: devicetelemetry
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "devicetelemetry.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "devicetelemetry.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "devicetelemetry.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "devicetelemetry.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "devicetelemetry.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "devicetelemetry.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "devicetelemetry.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "devicetelemetry.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "devicetelemetry.name" . }}
|
||||
chart: {{ template "devicetelemetry.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "devicetelemetry.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "devicetelemetry.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if .Values.probes.enabled }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 900
|
||||
timeoutSeconds: 300
|
||||
successThreshold: 60
|
||||
initialDelaySeconds: 900
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 900
|
||||
timeoutSeconds: 300
|
||||
initialDelaySeconds: 900
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "devicetelemetry.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "devicetelemetry.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.externalPort -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "devicetelemetry.name" . }}
|
||||
chart: {{ template "devicetelemetry.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $servicePort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "devicetelemetry.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc}}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "devicetelemetry.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "devicetelemetry.name" . }}
|
||||
chart: {{ template "devicetelemetry.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "devicetelemetry.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,80 @@
|
|||
# Default values for devicetelemetry.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: devicetelemetry
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/telemetry-dotnet
|
||||
tag: testing
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
service:
|
||||
type: ClusterIP
|
||||
externalPort: 80
|
||||
internalPort: 9004
|
||||
|
||||
#disableProbes:
|
||||
# enabled: false
|
||||
ingress:
|
||||
enabled: true
|
||||
#annotations:
|
||||
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /devicetelemetry
|
||||
hosts:
|
||||
- DNSNAME
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
secrets:
|
||||
devicetelemetry:
|
||||
PCS_TELEMETRY_DOCUMENTDB_CONNSTRING: PCS_TELEMETRY_DOCUMENTDB_CONNSTRING
|
||||
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||
PCS_AUTH_WEBSERVICE_URL: PCS_AUTH_WEBSERVICE_URL
|
||||
PCS_AAD_TENANT: PCS_AAD_TENANT
|
||||
PCS_AAD_APPID: PCS_AAD_APPID
|
||||
PCS_AAD_APPSECRET: PCS_AAD_APPSECRET
|
||||
PCS_TELEMETRY_STORAGE_TYPE: PCS_TELEMETRY_STORAGE_TYPE
|
||||
PCS_TSI_FQDN: PCS_TSI_FQDN
|
||||
PCS_DIAGNOSTICS_WEBSERVICE_URL: PCS_DIAGNOSTICS_WEBSERVICE_URL
|
||||
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
#
|
||||
probes:
|
||||
enabled: false
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
sh delete.sh
|
||||
sleep 5
|
||||
sh deploy.sh
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: certmanager.k8s.io/v1alpha1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: tls-secret
|
||||
spec:
|
||||
secretName: tls-secret
|
||||
dnsNames:
|
||||
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||
acme:
|
||||
config:
|
||||
- http01:
|
||||
ingressClass: nginx
|
||||
domains:
|
||||
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||
issuerRef:
|
||||
name: letsencrypt-prod
|
||||
kind: ClusterIssuer
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: certmanager.k8s.io/v1alpha1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: nobody@nobody.com
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod
|
||||
http01: {}
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Public IP address of your ingress controller
|
||||
IP="NGINXIP"
|
||||
|
||||
# Name to associate with public IP address
|
||||
DNSNAME="DNSGIVENNAME"
|
||||
|
||||
# Get the resource-id of the public ip
|
||||
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)
|
||||
|
||||
# Update public ip address with DNS name
|
||||
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: tiller
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tiller
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tiller
|
||||
namespace: kube-system
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
kubectl create -f helm-rbac.yaml
|
||||
|
||||
helm init --service-account tiller
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
helm install stable/nginx-ingress --namespace kube-system
|
||||
|
||||
echo "Waiting for nginx controller to acquire PUBLIC ip ....."
|
||||
sleep 20
|
||||
###########
|
||||
###HTTPS Controller
|
||||
##########
|
||||
|
||||
IP=`kubectl get service -l app=nginx-ingress --namespace kube-system | sed -n '/controller/s/ \+/ /gp' | cut -d" " -f4`
|
||||
|
||||
echo "INGRESS NGINX public IP is:"
|
||||
echo $IP
|
||||
|
||||
sed -i.bak s/NGINXIP/$IP/g configure-dns.sh
|
||||
|
||||
sed -i.bak1 s/DNSGIVENNAME/$1/g configure-dns.sh
|
||||
|
||||
echo "Configuring DNS ...."
|
||||
sh configure-dns.sh
|
||||
|
||||
mv configure-dns.sh.bak configure-dns.sh
|
||||
|
||||
rm -rf configure-dns.sh.bak1
|
||||
|
||||
echo "Installing cert manager"
|
||||
|
||||
helm install stable/cert-manager --set ingressShim.defaultIssuerName=letsencrypt --set ingressShim.defaultIssuerKind=ClusterIssuer
|
||||
|
||||
echo "Creating SSL cert issuer in cluster ..."
|
||||
|
||||
kubectl apply -f cluster-issuer.yaml
|
||||
|
||||
sed -i.bak s/DNSGIVENNAME/$1/g certificates.yaml
|
||||
|
||||
sed -i.bak1 s/REGION/$2/g certificates.yaml
|
||||
|
||||
mv certificates.yaml.bak certificates.yaml
|
||||
|
||||
rm -rf certificates.yaml.bak1
|
||||
|
||||
echo "Creating certificates resources ...."
|
||||
|
||||
kubectl apply -f certificates.yaml
|
||||
|
||||
echo "Creating Remote Monitoring Nginx controller"
|
||||
|
||||
sed -i.bak s/DNSGIVENNAME/$1/g rm-ingress.yaml
|
||||
|
||||
sed -i.bak s/REGION/$2/g rm-ingress.yaml
|
||||
|
||||
kubectl apply -f rm-ingress.yaml
|
||||
|
||||
mv rm-ingress.yaml.bak rm-ingress.yaml
|
||||
|
||||
rm -rf rm-ingress.yaml.bak1
|
|
@ -0,0 +1,53 @@
|
|||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: rm-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
spec:
|
||||
backend:
|
||||
serviceName: webui
|
||||
servicePort: 10080
|
||||
tls:
|
||||
- hosts:
|
||||
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||
secretName: tls-secret
|
||||
rules:
|
||||
- host: DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||
http:
|
||||
paths:
|
||||
- path: /storageadapter/(.*)
|
||||
backend:
|
||||
serviceName: storageadapter
|
||||
servicePort: 80
|
||||
- path: /iothubmanager/*
|
||||
backend:
|
||||
serviceName: iothubmanager
|
||||
servicePort: 80
|
||||
- path: /telemetry/*
|
||||
backend:
|
||||
serviceName: devicetelemetry
|
||||
servicePort: 80
|
||||
- path: /devicesimulation/*
|
||||
backend:
|
||||
serviceName: simulation
|
||||
servicePort: 80
|
||||
- path: /config/*
|
||||
backend:
|
||||
serviceName: config
|
||||
servicePort: 80
|
||||
- path: /asamanager/(.*)
|
||||
backend:
|
||||
serviceName: asamanager
|
||||
servicePort: 80
|
||||
- path: /auth/(.*)
|
||||
backend:
|
||||
serviceName: auth
|
||||
servicePort: 80
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: webui
|
||||
servicePort: 10080
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: iothubmanager
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "iothubmanager.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "iothubmanager.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "iothubmanager.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "iothubmanager.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "iothubmanager.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "iothubmanager.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "iothubmanager.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,76 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "iothubmanager.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "iothubmanager.name" . }}
|
||||
chart: {{ template "iothubmanager.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "iothubmanager.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "iothubmanager.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if not .Values.disableProbes }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "iothubmanager.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "iothubmanager.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "iothubmanager.name" . }}
|
||||
chart: {{ template "iothubmanager.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: http
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "iothubmanager.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "iothubmanager.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "iothubmanager.name" . }}
|
||||
chart: {{ template "iothubmanager.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "iothubmanager.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,68 @@
|
|||
# Default values for iothubmanager.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: iothubmanager
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/iothub-manager-dotnet
|
||||
tag: testing
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
service:
|
||||
type: ClusterIP
|
||||
externalPort: 80
|
||||
internalPort: 9002
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
#annotations:
|
||||
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /iothubmanager
|
||||
hosts:
|
||||
- DNSNAME
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.locam
|
||||
secrets:
|
||||
iothubmanager:
|
||||
PCS_AUTH_WEBSERVICE_URL: PCS_AUTH_WEBSERVICE_URL
|
||||
PCS_IOTHUB_CONNSTRING: PCS_IOTHUB_CONNSTRING
|
||||
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: reverse-proxy
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "reverse-proxy.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "reverse-proxy.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "reverse-proxy.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "reverse-proxy.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "reverse-proxy.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "reverse-proxy.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "reverse-proxy.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "reverse-proxy.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "reverse-proxy.name" . }}
|
||||
chart: {{ template "reverse-proxy.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "reverse-proxy.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "reverse-proxy.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
volumes:
|
||||
- name: certs-volume
|
||||
configMap:
|
||||
name: cert-config
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
volumeMounts:
|
||||
- name: certs-volume
|
||||
mountPath: /app/certs
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 10080
|
||||
protocol: TCP
|
||||
{{- if .Values.probes.enabled }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "reverse-proxy.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "reverse-proxy.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "reverse-proxy.name" . }}
|
||||
chart: {{ template "reverse-proxy.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: http
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "reverse-proxy.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "reverse-proxy.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "reverse-proxy.name" . }}
|
||||
chart: {{ template "reverse-proxy.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
- port: {{ .Values.service.externalHttpsPort }}
|
||||
targetPort: {{ .Values.service.internalHttpsPort }}
|
||||
protocol: TCP
|
||||
name: https
|
||||
selector:
|
||||
app: {{ template "reverse-proxy.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,70 @@
|
|||
# Default values for reverse-proxy.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: reverse-proxy
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/remote-monitoring-nginx
|
||||
tag: testing
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
#
|
||||
probes:
|
||||
enabled: false
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
internalPort: 80
|
||||
externalPort: 10080
|
||||
internalHttpsPort: 443
|
||||
externalHttpsPort: 10443
|
||||
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
#annotations:
|
||||
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /
|
||||
hosts:
|
||||
- rm-aks-test.eastus.cloudapp.azure.com
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
secrets: {}
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: simulation
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "simulation.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "simulation.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "simulation.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "simulation.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "simulation.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "simulation.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "simulation.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "simulation.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "simulation.name" . }}
|
||||
chart: {{ template "simulation.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "simulation.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "simulation.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if .Values.probes.enabled }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 600
|
||||
timeoutSeconds: 10
|
||||
successThreshold: 5
|
||||
initialDelaySeconds: 300
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 600
|
||||
timeoutSeconds: 10
|
||||
initialDelaySeconds: 300
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "simulation.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "simulation.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "simulation.name" . }}
|
||||
chart: {{ template "simulation.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: http
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
{{- $root := . }}
|
||||
{{- range $name, $values := .Values.secrets }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "simulation.fullname" $root }}-{{ $name | lower }}
|
||||
data:
|
||||
{{- range $key, $value := $values }}
|
||||
{{ $key }}: {{ $value | b64enc }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "simulation.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "simulation.name" . }}
|
||||
chart: {{ template "simulation.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "simulation.name" . }}
|
||||
release: {{ .Release.Name }}
|
|
@ -0,0 +1,72 @@
|
|||
# Default values for simulation.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
fullnameOverride: simulation
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: azureiotpcs/device-simulation-dotnet
|
||||
tag: DS-1.0.2
|
||||
pullPolicy: Always
|
||||
imagePullSecrets: []
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
#
|
||||
# This uses credentials from secret "myRegistryKeySecretName".
|
||||
# - name: myRegistryKeySecretName
|
||||
service:
|
||||
type: ClusterIP
|
||||
externalPort: 80
|
||||
internalPort: 9003
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
#annotations:
|
||||
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /simulation
|
||||
hosts:
|
||||
- DNSNAME
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
secrets:
|
||||
simulation:
|
||||
PCS_IOTHUB_CONNSTRING: PCS_IOTHUB_CONNSTRING
|
||||
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||
# Optionally specify a set of secret objects whose values
|
||||
# will be injected as environment variables by default.
|
||||
# You should add this section to a file like secrets.yaml
|
||||
# that is explicitly NOT committed to source code control
|
||||
# and then include it as part of your helm install step.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
#
|
||||
# This creates a secret "mysecret" and injects "mypassword"
|
||||
# as the environment variable mysecret_mypassword=password.
|
||||
# mysecret:
|
||||
# mypassword: password
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
#
|
||||
probes:
|
||||
enabled: false
|
||||
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: storageadapter
|
||||
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "storageadapter.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "storageadapter.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "storageadapter.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "storageadapter.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
|
@ -0,0 +1,32 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "storageadapter.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "storageadapter.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "storageadapter.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
|
@ -0,0 +1,77 @@
|
|||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "storageadapter.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "storageadapter.name" . }}
|
||||
chart: {{ template "storageadapter.chart" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "storageadapter.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "storageadapter.name" . }}
|
||||
draft: {{ default "draft-app" .Values.draft }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
buildID: {{ .Values.buildID }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.internalPort }}
|
||||
protocol: TCP
|
||||
{{- if not .Values.disableProbes }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/status
|
||||
port: http
|
||||
periodSeconds: 120
|
||||
initialDelaySeconds: 300
|
||||
{{- end }}
|
||||
env:
|
||||
{{- $root := . }}
|
||||
{{- range $ref, $values := .Values.secrets }}
|
||||
{{- range $key, $value := $values }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "storageadapter.fullname" $root }}-{{ $ref | lower }}
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "storageadapter.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.externalPort -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "storageadapter.name" . }}
|
||||
chart: {{ template "storageadapter.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $servicePort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче