Merge branch 'master' into integration_test_fix

This commit is contained in:
sushilraje 2019-01-22 17:07:33 -08:00 коммит произвёл GitHub
Родитель 5670ff1989 2d70bff103
Коммит 9550f338fa
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
121 изменённых файлов: 3218 добавлений и 92 удалений

Просмотреть файл

@ -21,10 +21,7 @@ PCS_CACHE="/tmp/azure/iotpcs/.cache"
compile() { compile() {
check_dependency_dotnet check_dependency_dotnet
cd $APP_HOME
./scripts/env-vars-check
header "Downloading dependencies..." header "Downloading dependencies..."
dotnet restore dotnet restore
@ -37,10 +34,13 @@ run_tests() {
cd $APP_HOME cd $APP_HOME
header "Running tests..." 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 for PROJ in $PROJECTS; do
echo "-- $PROJ" PROJ=${PROJ//\\/\/}
dotnet test --configuration $CONFIGURATION $PROJ PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
echo "-- $PROJ"
dotnet test --configuration $CONFIGURATION $PROJ
done done
} }

Просмотреть файл

@ -34,10 +34,13 @@ run_tests() {
cd $APP_HOME cd $APP_HOME
header "Running tests..." header "Running tests..."
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test') PROJECTS=$(dotnet sln auth.sln list | grep '\.Test')
for PROJ in $PROJECTS; do for PROJ in $PROJECTS; do
echo "-- $PROJ" PROJ=${PROJ//\\/\/}
dotnet test --configuration $CONFIGURATION $PROJ PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
echo "-- $PROJ"
dotnet test --configuration $CONFIGURATION $PROJ
done done
} }

Просмотреть файл

@ -45,7 +45,8 @@ namespace WebService.Test.Controllers
IFormFile file = null; IFormFile file = null;
if (isValidFileProvided) if (isValidFileProvided)
{ {
file = this.CreateSampleFile(filename); bool isEdgePackage = (type == "EdgeManifest") ? true : false;
file = this.CreateSampleFile(filename, isEdgePackage);
} }
Enum.TryParse(type, out PackageType pckgType); Enum.TryParse(type, out PackageType pckgType);
@ -195,13 +196,20 @@ namespace WebService.Test.Controllers
Times.Once); 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(); var stream = new MemoryStream();
stream.WriteByte(100); var writer = new StreamWriter(stream);
stream.Flush(); var package = isEdgePackage ? edgePackage : admPackage;
writer.Write(package);
writer.Flush();
stream.Position = 0; 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 cd $APP_HOME
header "Running tests..." header "Running tests..."
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test') PROJECTS=$(dotnet sln config.sln list | grep '\.Test')
for PROJ in $PROJECTS; do for PROJ in $PROJECTS; do
echo "-- $PROJ" PROJ=${PROJ//\\/\/}
dotnet test --configuration $CONFIGURATION $PROJ PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
echo "-- $PROJ"
dotnet test --configuration $CONFIGURATION $PROJ
done done
} }

Просмотреть файл

@ -13,14 +13,22 @@ run_container() {
echo "Starting Config service ..." echo "Starting Config service ..."
docker run -it -p 9005:9005 \ docker run -it -p 9005:9005 \
-e PCS_AUTH_WEBSERVICE_URL \
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \ -e PCS_STORAGEADAPTER_WEBSERVICE_URL \
-e PCS_DEVICESIMULATION_WEBSERVICE_URL \ -e PCS_DEVICESIMULATION_WEBSERVICE_URL \
-e PCS_TELEMETRY_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_OFFICE365_CONNECTION_URL \
-e PCS_SOLUTION_NAME \ -e PCS_SOLUTION_NAME \
-e PCS_SUBSCRIPTION_ID \ -e PCS_SUBSCRIPTION_ID \
-e PCS_ARM_ENDPOINT_URL \ -e PCS_ARM_ENDPOINT_URL \
-e PCS_SEED_TEMPLATE \
"$DOCKER_IMAGE:testing" "$DOCKER_IMAGE:testing"
} }

Просмотреть файл

@ -19,14 +19,22 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
:: Start the application :: Start the application
echo Starting Config web service ... echo Starting Config web service ...
docker run -it -p 9005:9005 ^ docker run -it -p 9005:9005 ^
-e PCS_AUTH_WEBSERVICE_URL ^
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^ -e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
-e PCS_DEVICESIMULATION_WEBSERVICE_URL ^ -e PCS_DEVICESIMULATION_WEBSERVICE_URL ^
-e PCS_TELEMETRY_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_OFFICE365_CONNECTION_URL ^
-e PCS_SOLUTION_NAME ^ -e PCS_SOLUTION_NAME ^
-e PCS_SUBSCRIPTION_ID ^ -e PCS_SUBSCRIPTION_ID ^
-e PCS_ARM_ENDPOINT_URL ^ -e PCS_ARM_ENDPOINT_URL ^
-e PCS_SEED_TEMPLATE ^
%DOCKER_IMAGE%:testing %DOCKER_IMAGE%:testing
:: - - - - - - - - - - - - - - :: - - - - - - - - - - - - - -

Просмотреть файл

@ -2,9 +2,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Azure.Documents; using Microsoft.Azure.Documents;
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services; 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.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)); 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=j&#X41vascript: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.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services; 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.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 Moq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Services.Test.helpers; using Services.Test.helpers;
@ -17,11 +22,23 @@ namespace Services.Test
private const int SKIP = 0; private const int SKIP = 0;
private const int LIMIT = 1000; 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() 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)] [Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
@ -29,9 +46,10 @@ namespace Services.Test
{ {
// Arrange // Arrange
this.ThereAreNoMessagesInStorage(); this.ThereAreNoMessagesInStorage();
var devices = new string[] { "device1" };
// Act // 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
Assert.Empty(list.Messages); Assert.Empty(list.Messages);
@ -43,18 +61,34 @@ namespace Services.Test
{ {
// Arrange // Arrange
this.ThereAreSomeMessagesInStorage(); this.ThereAreSomeMessagesInStorage();
var devices = new string[] { "device1" };
// Act // 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
Assert.NotEmpty(list.Messages); Assert.NotEmpty(list.Messages);
Assert.NotEmpty(list.Properties); 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=j&#X41vascript:alert('test2')>"
};
// Act & Assert
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.messages.ListAsync(null, null, xssString, 0, LIMIT, xssList.ToArray()));
}
private void ThereAreNoMessagesInStorage() 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()); .ReturnsAsync(new MessageList());
} }
@ -75,7 +109,7 @@ namespace Services.Test
sampleProperties.Add("data.sample_unit"); sampleProperties.Add("data.sample_unit");
sampleProperties.Add("data.sample_speed"); 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)); .ReturnsAsync(new MessageList(sampleMessages, sampleProperties));
} }
} }

Просмотреть файл

@ -18,7 +18,6 @@ using Moq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Services.Test.helpers; using Services.Test.helpers;
using Xunit; using Xunit;
using Type = System.Type;
namespace Services.Test namespace Services.Test
{ {
@ -405,6 +404,74 @@ namespace Services.Test
this.httpClientMock.Verify(x => x.PostAsync(It.IsAny<HttpRequest>()), Times.Exactly(4)); 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=j&#X41vascript: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() private void ThereAreNoRulessInStorage()
{ {
this.rulesMock.Setup(x => x.GetListAsync(null, 0, LIMIT, null, false)) this.rulesMock.Setup(x => x.GetListAsync(null, 0, LIMIT, null, false))
@ -412,6 +479,14 @@ namespace Services.Test
} }
private void ThereAreSomeRulesInStorage() 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> var sampleConditions = new List<Condition>
{ {
@ -440,7 +515,7 @@ namespace Services.Test
{ {
Name = "Sample 1", Name = "Sample 1",
Enabled = true, Enabled = true,
Description = "Sample description 1", Description = "Sample description 1 -- Pressure >= 298",
GroupId = "Prototyping devices", GroupId = "Prototyping devices",
Severity = SeverityType.Critical, Severity = SeverityType.Critical,
Conditions = sampleConditions, Conditions = sampleConditions,
@ -455,11 +530,22 @@ namespace Services.Test
Severity = SeverityType.Warning, Severity = SeverityType.Warning,
Conditions = sampleConditions, Conditions = sampleConditions,
Actions = sampleActions 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)) return sampleRules;
.ReturnsAsync(sampleRules);
} }
/** /**

Просмотреть файл

@ -2,10 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net; using System.Net;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Azure.Documents; using Microsoft.Azure.Documents;
@ -55,8 +52,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public class Alarms : IAlarms public class Alarms : IAlarms
{ {
private const string INVALID_CHARACTER = @"[^A-Za-z0-9:;.,_\-]";
private readonly ILogger log; private readonly ILogger log;
private readonly IStorageClient storageClient; private readonly IStorageClient storageClient;
@ -90,11 +85,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public Alarm Get(string id) public Alarm Get(string id)
{ {
if (Regex.IsMatch(id, INVALID_CHARACTER))
{
throw new InvalidInputException("id contains illegal characters.");
}
Document doc = this.GetDocumentById(id); Document doc = this.GetDocumentById(id);
return new Alarm(doc); return new Alarm(doc);
} }
@ -160,11 +150,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
limit, limit,
devices, DEVICE_ID_KEY); 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 }); this.log.Debug("Created Alarm By Rule Query", () => new { sql });
FeedOptions queryOptions = new FeedOptions(); FeedOptions queryOptions = new FeedOptions();
@ -220,10 +205,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public async Task<Alarm> UpdateAsync(string id, string status) public async Task<Alarm> UpdateAsync(string id, string status)
{ {
if (Regex.IsMatch(id, INVALID_CHARACTER)) InputValidator.Validate(id);
{ InputValidator.Validate(status);
throw new InvalidInputException("id contains illegal characters.");
}
Document document = this.GetDocumentById(id); Document document = this.GetDocumentById(id);
document.SetPropertyValue(STATUS_KEY, status); document.SetPropertyValue(STATUS_KEY, status);
@ -238,10 +221,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
private Document GetDocumentById(string id) private Document GetDocumentById(string id)
{ {
if (Regex.IsMatch(id, INVALID_CHARACTER)) InputValidator.Validate(id);
{
throw new InvalidInputException("id contains illegal characters.");
}
var query = new SqlQuerySpec( var query = new SqlQuerySpec(
"SELECT * FROM c WHERE c.id=@id", "SELECT * FROM c WHERE c.id=@id",
@ -268,6 +248,11 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public async Task Delete(List<string> ids) public async Task Delete(List<string> ids)
{ {
foreach(var id in ids)
{
InputValidator.Validate(id);
}
Task[] taskList = new Task[ids.Count]; Task[] taskList = new Task[ids.Count];
for (int i = 0; i < ids.Count; i++) for (int i = 0; i < ids.Count; i++)
{ {
@ -292,6 +277,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
*/ */
public async Task DeleteAsync(string id) public async Task DeleteAsync(string id)
{ {
InputValidator.Validate(id);
int retryCount = 0; int retryCount = 0;
while (retryCount < this.maxDeleteRetryCount) 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 schemaName);
ValidateInput(ref fromProperty); ValidateInput(ref fromProperty);
ValidateInput(ref toProperty); ValidateInput(ref toProperty);
ValidateInput(ref order);
ValidateInput(ref orderProperty); ValidateInput(ref orderProperty);
for (int i = 0; i < devices.Length; i++)
{
ValidateInput(ref devices[i]);
}
ValidateInput(ref devicesProperty); ValidateInput(ref devicesProperty);
var sqlParameterCollection = new SqlParameterCollection(); var sqlParameterCollection = new SqlParameterCollection();

Просмотреть файл

@ -1,8 +1,8 @@
// Copyright (c) Microsoft. All rights reserved. // Copyright (c) Microsoft. All rights reserved.
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Azure.Documents; using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client; using Microsoft.Azure.Documents.Client;
@ -68,6 +68,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
int limit, int limit,
string[] devices) string[] devices)
{ {
InputValidator.Validate(order);
foreach (var device in devices)
{
InputValidator.Validate(device);
}
return this.timeSeriesEnabled ? return this.timeSeriesEnabled ?
await this.GetListFromTimeSeriesAsync(from, to, order, skip, limit, devices) : await this.GetListFromTimeSeriesAsync(from, to, order, skip, limit, devices) :
this.GetListFromCosmosDb(from, to, order, skip, limit, devices); this.GetListFromCosmosDb(from, to, order, skip, limit, devices);

Просмотреть файл

@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Helpers;
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models.Actions; using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models.Actions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
@ -11,6 +12,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models
public class Rule : IComparable<Rule> public class Rule : IComparable<Rule>
{ {
private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:sszzz"; private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:sszzz";
// Comes from the StorageAdapter document and not the serialized rule // Comes from the StorageAdapter document and not the serialized rule
[JsonIgnore] [JsonIgnore]
public string ETag { get; set; } = string.Empty; public string ETag { get; set; } = string.Empty;
@ -41,6 +43,11 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Models
return DateTimeOffset.Parse(other.DateCreated) return DateTimeOffset.Parse(other.DateCreated)
.CompareTo(DateTimeOffset.Parse(this.DateCreated)); .CompareTo(DateTimeOffset.Parse(this.DateCreated));
} }
public void Validate()
{
InputValidator.Validate(this.Id);
}
} }
public enum CalculationType public enum CalculationType

Просмотреть файл

@ -4,7 +4,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Diagnostics; using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Exceptions; using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Exceptions;
@ -49,7 +48,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public class Rules : IRules public class Rules : IRules
{ {
private const string STORAGE_COLLECTION = "rules"; 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 const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:sszzz";
private readonly IStorageAdapterClient storage; private readonly IStorageAdapterClient storage;
@ -91,6 +89,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public async Task DeleteAsync(string id) public async Task DeleteAsync(string id)
{ {
InputValidator.Validate(id);
Rule existing; Rule existing;
try try
{ {
@ -125,11 +125,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public async Task<Rule> GetAsync(string id) public async Task<Rule> GetAsync(string id)
{ {
if (Regex.IsMatch(id, INVALID_CHARACTER)) InputValidator.Validate(id);
{
this.log.Debug("id contains illegal characters.", () => new { id });
throw new InvalidInputException("id contains illegal characters.");
}
var item = await this.storage.GetAsync(STORAGE_COLLECTION, id); var item = await this.storage.GetAsync(STORAGE_COLLECTION, id);
var rule = this.Deserialize(item.Data); var rule = this.Deserialize(item.Data);
@ -147,6 +143,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
string groupId, string groupId,
bool includeDeleted) bool includeDeleted)
{ {
InputValidator.Validate(order);
if (!string.IsNullOrEmpty(groupId))
{
InputValidator.Validate(groupId);
}
var data = await this.storage.GetAllAsync(STORAGE_COLLECTION); var data = await this.storage.GetAllAsync(STORAGE_COLLECTION);
var ruleList = new List<Rule>(); var ruleList = new List<Rule>();
foreach (var item in data.Items) foreach (var item in data.Items)
@ -205,6 +207,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
int limit, int limit,
string[] devices) string[] devices)
{ {
InputValidator.Validate(order);
foreach (var device in devices)
{
InputValidator.Validate(device);
}
var alarmCountByRuleList = new List<AlarmCountByRule>(); var alarmCountByRuleList = new List<AlarmCountByRule>();
// get list of rules // get list of rules
@ -246,6 +254,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
{ {
throw new InvalidInputException("Rule not provided."); throw new InvalidInputException("Rule not provided.");
} }
rule.Validate();
// Ensure dates are correct // Ensure dates are correct
rule.DateCreated = DateTimeOffset.UtcNow.ToString(DATE_FORMAT); rule.DateCreated = DateTimeOffset.UtcNow.ToString(DATE_FORMAT);
@ -265,6 +274,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services
public async Task<Rule> UpsertIfNotDeletedAsync(Rule rule) public async Task<Rule> UpsertIfNotDeletedAsync(Rule rule)
{ {
rule.Validate();
if (rule == null) if (rule == null)
{ {
throw new InvalidInputException("Rule not provided."); throw new InvalidInputException("Rule not provided.");

Просмотреть файл

@ -22,9 +22,6 @@ PCS_CACHE="/tmp/azure/iotpcs/.cache"
compile() { compile() {
check_dependency_dotnet check_dependency_dotnet
cd $APP_HOME
./scripts/env-vars-check
header "Downloading dependencies..." header "Downloading dependencies..."
dotnet restore dotnet restore
@ -37,10 +34,13 @@ run_tests() {
cd $APP_HOME cd $APP_HOME
header "Running tests..." header "Running tests..."
PROJECTS=$(dotnet sln list | grep 'csproj$' | grep '\.Test') PROJECTS=$(dotnet sln telemetry.sln list | grep '\.Test')
for PROJ in $PROJECTS; do for PROJ in $PROJECTS; do
echo "-- $PROJ" PROJ=${PROJ//\\/\/}
dotnet test --configuration $CONFIGURATION $PROJ PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
echo "-- $PROJ"
dotnet test --configuration $CONFIGURATION $PROJ
done done
} }

Просмотреть файл

@ -16,11 +16,15 @@ run_container() {
echo "Starting Telemetry service..." echo "Starting Telemetry service..."
docker run -it -p 9004:9004 \ docker run -it -p 9004:9004 \
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
-e PCS_AUTH_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_ISSUER \
-e PCS_AUTH_AUDIENCE \ -e PCS_AUTH_AUDIENCE \
-e PCS_AUTH_REQUIRED \
-e PCS_CORS_WHITELIST \
-e PCS_APPLICATION_SECRET \
-e PCS_AAD_TENANT \ -e PCS_AAD_TENANT \
-e PCS_AAD_APPID \ -e PCS_AAD_APPID \
-e PCS_AAD_APPSECRET \ -e PCS_AAD_APPSECRET \
@ -30,7 +34,7 @@ run_container() {
-e PCS_ACTION_EVENTHUB_CONNSTRING \ -e PCS_ACTION_EVENTHUB_CONNSTRING \
-e PCS_ACTION_EVENTHUB_NAME \ -e PCS_ACTION_EVENTHUB_NAME \
-e PCS_LOGICAPP_ENDPOINT_URL \ -e PCS_LOGICAPP_ENDPOINT_URL \
-e PCS_SOLUTION_NAME \ -e PCS_SOLUTION_WEBSITE_URL \
"$DOCKER_IMAGE:testing" "$DOCKER_IMAGE:testing"
} }

Просмотреть файл

@ -21,11 +21,15 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
:: Start the application :: Start the application
echo Starting Telemetry service... echo Starting Telemetry service...
docker run -it -p 9004:9004 ^ docker run -it -p 9004:9004 ^
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING ^
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
-e PCS_AUTH_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_ISSUER ^
-e PCS_AUTH_AUDIENCE ^ -e PCS_AUTH_AUDIENCE ^
-e PCS_AUTH_REQUIRED ^
-e PCS_CORS_WHITELIST ^
-e PCS_APPLICATION_SECRET ^
-e PCS_AAD_TENANT ^ -e PCS_AAD_TENANT ^
-e PCS_AAD_APPID ^ -e PCS_AAD_APPID ^
-e PCS_AAD_APPSECRET ^ -e PCS_AAD_APPSECRET ^
@ -35,7 +39,7 @@ docker run -it -p 9004:9004 ^
-e PCS_ACTION_EVENTHUB_CONNSTRING ^ -e PCS_ACTION_EVENTHUB_CONNSTRING ^
-e PCS_ACTION_EVENTHUB_NAME ^ -e PCS_ACTION_EVENTHUB_NAME ^
-e PCS_LOGICAPP_ENDPOINT_URL ^ -e PCS_LOGICAPP_ENDPOINT_URL ^
-e PCS_SOLUTION_NAME ^ -e PCS_SOLUTION_WEBSITE_URL ^
%DOCKER_IMAGE%:testing %DOCKER_IMAGE%:testing
:: - - - - - - - - - - - - - - :: - - - - - - - - - - - - - -

2
docs/CICD.md Normal file
Просмотреть файл

@ -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;
using System.Threading; 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 // When generating the cache, allow some time to finish, at least one minute
private const int CACHE_TIMEOUT_SECS = 90; private const int CACHE_TIMEOUT_SECS = 90;
private readonly IDeviceProperties deviceProperties; private readonly IDeviceProperties deviceProperties;
private readonly ILogger log; private readonly ILogger log;
private Timer cacheUpdateTimer;
public Agent( public Agent(
IDeviceProperties deviceProperties, IDeviceProperties deviceProperties,
@ -66,7 +68,7 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.RecurringTasksAgent
try try
{ {
this.log.Info("Scheduling a DeviceProperties cache update", () => new { CACHE_UPDATE_SECS }); this.log.Info("Scheduling a DeviceProperties cache update", () => new { CACHE_UPDATE_SECS });
var unused = new Timer( this.cacheUpdateTimer = new Timer(
this.UpdateDevicePropertiesCache, this.UpdateDevicePropertiesCache,
null, null,
1000 * CACHE_UPDATE_SECS, 1000 * CACHE_UPDATE_SECS,

Просмотреть файл

@ -20,9 +20,6 @@ PCS_CACHE="/tmp/azure/iotpcs/.cache"
compile() { compile() {
check_dependency_dotnet check_dependency_dotnet
cd $APP_HOME
./scripts/env-vars-check
header "Downloading dependencies..." header "Downloading dependencies..."
dotnet restore dotnet restore
@ -35,10 +32,13 @@ run_tests() {
cd $APP_HOME cd $APP_HOME
header "Running tests..." 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 for PROJ in $PROJECTS; do
echo "-- $PROJ" PROJ=${PROJ//\\/\/}
dotnet test --configuration $CONFIGURATION $PROJ PROJ=$(echo $PROJ | sed 's/[^a-zA-Z\.\/]//g')
echo "-- $PROJ"
dotnet test --configuration $CONFIGURATION $PROJ
done 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: {}

26
scripts/cd/delete.sh Executable file
Просмотреть файл

@ -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

39
scripts/cd/deploy.sh Executable file
Просмотреть файл

@ -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: {}

5
scripts/cd/helm_install.sh Executable file
Просмотреть файл

@ -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 }}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше