Merge branch 'master' into integration_test_fix
This commit is contained in:
Коммит
9550f338fa
|
@ -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=jAvascript:alert('test2')>"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.alarms.DeleteAsync(xssString));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.alarms.Delete(xssList));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.alarms.UpdateAsync(xssString, xssString));
|
||||||
|
Assert.Throws<InvalidInputException>(() => this.alarms.GetCountByRule(xssString, DateTimeOffset.MaxValue, DateTimeOffset.MaxValue, xssList.ToArray()));
|
||||||
|
Assert.Throws<InvalidInputException>(() => this.alarms.List(null, null, xssString, 0, 1, xssList.ToArray()));
|
||||||
|
Assert.Throws<InvalidInputException>(() => this.alarms.ListByRule(xssString, DateTimeOffset.MaxValue, DateTimeOffset.MaxValue, xssString, 0, 1, xssList.ToArray()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,12 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.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=jAvascript: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=jAvascript:alert('test2')>"
|
||||||
|
};
|
||||||
|
|
||||||
|
var rule = new Rule()
|
||||||
|
{
|
||||||
|
ETag = xssString,
|
||||||
|
Id = xssString,
|
||||||
|
Name = xssString,
|
||||||
|
DateCreated = xssString,
|
||||||
|
DateModified = xssString,
|
||||||
|
Enabled = true,
|
||||||
|
Description = xssString,
|
||||||
|
GroupId = xssString,
|
||||||
|
Severity = SeverityType.Critical,
|
||||||
|
Conditions = new List<Condition>
|
||||||
|
{
|
||||||
|
new Condition()
|
||||||
|
{
|
||||||
|
Field = "sample_conddition",
|
||||||
|
Operator = OperatorType.Equals,
|
||||||
|
Value = "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Actions = new List<IAction>
|
||||||
|
{
|
||||||
|
new EmailAction(
|
||||||
|
new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "recipients", new Newtonsoft.Json.Linq.JArray(){ "sampleEmail@gmail.com", "sampleEmail2@gmail.com" } },
|
||||||
|
{ "subject", "Test Email" },
|
||||||
|
{ "notes", "Test Email Notes." }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.DeleteAsync(xssString));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.DeleteAsync(xssString));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.GetAsync(xssString));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.GetListAsync(xssString, 0, 1, xssString, false));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.GetAlarmCountForListAsync(null, null, xssString, 0, LIMIT, xssList.ToArray()));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.CreateAsync(rule));
|
||||||
|
await Assert.ThrowsAsync<InvalidInputException>(async () => await this.rules.UpsertIfNotDeletedAsync(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
|
||||||
|
public void InputValidationPassesWithValidRule()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
this.ThereAreSomeRulesInStorage();
|
||||||
|
|
||||||
|
List<Rule> rulesList = this.GetSampleRulesList();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
foreach (var rule in rulesList)
|
||||||
|
{
|
||||||
|
rule.Validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ThereAreNoRulessInStorage()
|
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
|
||||||
|
|
||||||
:: - - - - - - - - - - - - - -
|
:: - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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: {}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/bash
|
||||||
|
####### helm delete release
|
||||||
|
echo "Config current context"
|
||||||
|
kubectl config current-context
|
||||||
|
|
||||||
|
echo "Deleting services from above context"
|
||||||
|
helm delete storageadapter
|
||||||
|
helm delete telemetry
|
||||||
|
helm delete iothubmanager
|
||||||
|
helm delete simulation
|
||||||
|
helm delete auth
|
||||||
|
helm delete webui
|
||||||
|
helm delete asamanager
|
||||||
|
helm delete config
|
||||||
|
####### helm purgedelete to ensure if above cmds don't work
|
||||||
|
helm del --purge storageadapter
|
||||||
|
helm del --purge telemetry
|
||||||
|
helm del --purge iothubmanager
|
||||||
|
helm del --purge simulation
|
||||||
|
helm del --purge auth
|
||||||
|
helm del --purge webui
|
||||||
|
helm del --purge asamanager
|
||||||
|
helm del --purge config
|
||||||
|
##################### Delete any other resources
|
||||||
|
kubectl delete secret storageadapter-storageadapter
|
||||||
|
exit 0
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/bin/bash
|
||||||
|
source .env
|
||||||
|
####### Install helm charts
|
||||||
|
install() {
|
||||||
|
# helm install --name storageadapter storageadapter/charts/storageadapter/ --set secrets.storageadapter.PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING=${PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING} --set-string secrets.storageadapter.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||||
|
|
||||||
|
helm install --name telemetry telemetry/charts/devicetelemetry/ --set secrets.devicetelemetry.PCS_TELEMETRY_DOCUMENTDB_CONNSTRING=${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING} --set secrets.devicetelemetry.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set secrets.devicetelemetry.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set secrets.devicetelemetry.PCS_AUTH_WEBSERVICE_URL=${PCS_AUTH_WEBSERVICE_URL} --set secrets.devicetelemetry.PCS_AAD_TENANT=${PCS_AAD_TENANT} --set secrets.devicetelemetry.PCS_AAD_APPID=${PCS_AAD_APPID} --set secrets.devicetelemetry.PCS_AAD_APPSECRET=${PCS_AAD_APPSECRET} --set secrets.devicetelemetry.PCS_TELEMETRY_STORAGE_TYPE=${PCS_TELEMETRY_STORAGE_TYPE} --set secrets.devicetelemetry.PCS_TSI_FQDN=${PCS_TSI_FQDN} --set-string secrets.devicetelemetry.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||||
|
|
||||||
|
helm install --name iothubmanager iothubmanager/charts/iothubmanager/ --set secrets.iothubmanager.PCS_IOTHUB_CONNSTRING=${PCS_IOTHUB_CONNSTRING} --set secrets.iothubmanager.PCS_AUTH_WEBSERVICE_URL=${PCS_AUTH_WEBSERVICE_URL} --set secrets.iothubmanager.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set-string secrets.iothubmanager.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||||
|
|
||||||
|
helm install --name simulation simulation/charts/simulation/ --set secrets.simulation.PCS_IOTHUB_CONNSTRING=${PCS_IOTHUB_CONNSTRING} --set secrets.simulation.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set-string secrets.simulation.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||||
|
|
||||||
|
helm install --name config config/charts/config --set secrets.config.PCS_DEVICESIMULATION_WEBSERVICE_URL=${PCS_DEVICESIMULATION_WEBSERVICE_URL} --set secrets.config.PCS_STORAGEADAPTER_WEBSERVICE_URL=${PCS_STORAGEADAPTER_WEBSERVICE_URL} --set secrets.config.PCS_TELEMETRY_WEBSERVICE_URL=${PCS_TELEMETRY_WEBSERVICE_URL} --set secrets.config.PCS_AZUREMAPS_KEY=${PCS_AZUREMAPS_KEY} --set secrets.config.PCS_AUTH_WEBSERVICE_URL=${PCS_AUTH_WEBSERVICE_URL} --set-string secrets.config.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED} --debug
|
||||||
|
|
||||||
|
helm install --name asamanager asamanager/charts/asamanager/ --set secrets.asamanager.PCS_ASA_DATA_AZUREBLOB_ACCOUNT=${PCS_ASA_DATA_AZUREBLOB_ACCOUNT} --set secrets.asamanager.PCS_ASA_DATA_AZUREBLOB_KEY=${PCS_ASA_DATA_AZUREBLOB_KEY} --set secrets.asamanager.PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX=${PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX} --set secrets.asamanager.PCS_EVENTHUB_CONNSTRING=${PCS_EVENTHUB_CONNSTRING} --set secrets.asamanager.PCS_EVENTHUB_NAME=${PCS_EVENTHUB_NAME} --set secrets.asamanager.PCS_TELEMETRY_DOCUMENTDB_CONNSTRING=${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING} --set secrets.asamanager.PCS_TELEMETRY_WEBSERVICE_URL=${PCS_TELEMETRY_WEBSERVICE_URL} --set secrets.asamanager.PCS_CONFIG_WEBSERVICE_URL=${PCS_CONFIG_WEBSERVICE_URL} --set secrets.asamanager.PCS_IOTHUBMANAGER_WEBSERVICE_URL=${PCS_IOTHUBMANAGER_WEBSERVICE_URL} --set secrets.asamanager.PCS_TELEMETRY_STORAGE_TYPE=${PCS_TELEMETRY_STORAGE_TYPE} --set-string secrets.asamanager.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED} --debug
|
||||||
|
|
||||||
|
helm install --name auth auth/charts/auth/ --set secrets.auth.PCS_AUTH_AUDIENCE=${PCS_AUTH_AUDIENCE} --set secrets.auth.PCS_AUTH_ISSUER=${PCS_AUTH_ISSUER}
|
||||||
|
|
||||||
|
helm install --name webui webui/charts/webui/ --set REACT_APP_BASE_SERVICE_URL=${REACT_APP_BASE_SERVICE_URL}
|
||||||
|
|
||||||
|
helm install --name reverse-proxy reverse-proxy/charts/reverse-proxy/
|
||||||
|
}
|
||||||
|
##########################
|
||||||
|
|
||||||
|
upgrade() {
|
||||||
|
helm upgrade --install --force storageadapter storageadapter/ --set secrets.storageadapter.PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING=${PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING} --set-string secrets.storageadapter.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED} --debug
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
must_run_once_more(){
|
||||||
|
#### Thisstep is required due to bug in helm https://github.com/helm/helm/issues/1479
|
||||||
|
helm install --name storageadapter storageadapter/ --set secrets.storageadapter.PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING=${PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING} --set-string secrets.storageadapter.PCS_AUTH_REQUIRED=${PCS_AUTH_REQUIRED}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
must_run_once_more
|
||||||
|
|
||||||
|
install
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
appVersion: "1.0"
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
name: devicetelemetry
|
||||||
|
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "devicetelemetry.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get svc -w {{ template "devicetelemetry.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "devicetelemetry.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "devicetelemetry.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl port-forward $POD_NAME 8080:80
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{/* vim: set filetype=mustache: */}}
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "devicetelemetry.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "devicetelemetry.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||||
|
{{- if contains $name .Release.Name -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "devicetelemetry.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,79 @@
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "devicetelemetry.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "devicetelemetry.name" . }}
|
||||||
|
chart: {{ template "devicetelemetry.chart" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "devicetelemetry.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "devicetelemetry.name" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
annotations:
|
||||||
|
buildID: {{ .Values.buildID }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.probes.enabled }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 900
|
||||||
|
timeoutSeconds: 300
|
||||||
|
successThreshold: 60
|
||||||
|
initialDelaySeconds: 900
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 900
|
||||||
|
timeoutSeconds: 300
|
||||||
|
initialDelaySeconds: 900
|
||||||
|
{{- end }}
|
||||||
|
env:
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $ref, $values := .Values.secrets }}
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ template "devicetelemetry.fullname" $root }}-{{ $ref | lower }}
|
||||||
|
key: {{ $key }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "devicetelemetry.fullname" . -}}
|
||||||
|
{{- $servicePort := .Values.service.externalPort -}}
|
||||||
|
{{- $ingressPath := .Values.ingress.path -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "devicetelemetry.name" . }}
|
||||||
|
chart: {{ template "devicetelemetry.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ . }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: {{ $ingressPath }}
|
||||||
|
backend:
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: {{ $servicePort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $name, $values := .Values.secrets }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ template "devicetelemetry.fullname" $root }}-{{ $name | lower }}
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
{{ $key }}: {{ $value | b64enc}}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ template "devicetelemetry.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "devicetelemetry.name" . }}
|
||||||
|
chart: {{ template "devicetelemetry.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.externalPort }}
|
||||||
|
targetPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: {{ template "devicetelemetry.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Default values for devicetelemetry.
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
fullnameOverride: devicetelemetry
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: azureiotpcs/telemetry-dotnet
|
||||||
|
tag: testing
|
||||||
|
pullPolicy: Always
|
||||||
|
imagePullSecrets: []
|
||||||
|
# Optionally specify an array of imagePullSecrets.
|
||||||
|
# Secrets must be manually created in the namespace.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||||
|
#
|
||||||
|
# This uses credentials from secret "myRegistryKeySecretName".
|
||||||
|
# - name: myRegistryKeySecretName
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
externalPort: 80
|
||||||
|
internalPort: 9004
|
||||||
|
|
||||||
|
#disableProbes:
|
||||||
|
# enabled: false
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
#annotations:
|
||||||
|
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /devicetelemetry
|
||||||
|
hosts:
|
||||||
|
- DNSNAME
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
secrets:
|
||||||
|
devicetelemetry:
|
||||||
|
PCS_TELEMETRY_DOCUMENTDB_CONNSTRING: PCS_TELEMETRY_DOCUMENTDB_CONNSTRING
|
||||||
|
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||||
|
PCS_AUTH_WEBSERVICE_URL: PCS_AUTH_WEBSERVICE_URL
|
||||||
|
PCS_AAD_TENANT: PCS_AAD_TENANT
|
||||||
|
PCS_AAD_APPID: PCS_AAD_APPID
|
||||||
|
PCS_AAD_APPSECRET: PCS_AAD_APPSECRET
|
||||||
|
PCS_TELEMETRY_STORAGE_TYPE: PCS_TELEMETRY_STORAGE_TYPE
|
||||||
|
PCS_TSI_FQDN: PCS_TSI_FQDN
|
||||||
|
PCS_DIAGNOSTICS_WEBSERVICE_URL: PCS_DIAGNOSTICS_WEBSERVICE_URL
|
||||||
|
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||||
|
# Optionally specify a set of secret objects whose values
|
||||||
|
# will be injected as environment variables by default.
|
||||||
|
# You should add this section to a file like secrets.yaml
|
||||||
|
# that is explicitly NOT committed to source code control
|
||||||
|
# and then include it as part of your helm install step.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||||
|
#
|
||||||
|
# This creates a secret "mysecret" and injects "mypassword"
|
||||||
|
# as the environment variable mysecret_mypassword=password.
|
||||||
|
# mysecret:
|
||||||
|
# mypassword: password
|
||||||
|
#
|
||||||
|
probes:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
resources: {}
|
||||||
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
|
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
sh delete.sh
|
||||||
|
sleep 5
|
||||||
|
sh deploy.sh
|
|
@ -0,0 +1,17 @@
|
||||||
|
apiVersion: certmanager.k8s.io/v1alpha1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: tls-secret
|
||||||
|
spec:
|
||||||
|
secretName: tls-secret
|
||||||
|
dnsNames:
|
||||||
|
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||||
|
acme:
|
||||||
|
config:
|
||||||
|
- http01:
|
||||||
|
ingressClass: nginx
|
||||||
|
domains:
|
||||||
|
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
|
@ -0,0 +1,11 @@
|
||||||
|
apiVersion: certmanager.k8s.io/v1alpha1
|
||||||
|
kind: ClusterIssuer
|
||||||
|
metadata:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
acme:
|
||||||
|
server: https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
email: nobody@nobody.com
|
||||||
|
privateKeySecretRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
http01: {}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Public IP address of your ingress controller
|
||||||
|
IP="NGINXIP"
|
||||||
|
|
||||||
|
# Name to associate with public IP address
|
||||||
|
DNSNAME="DNSGIVENNAME"
|
||||||
|
|
||||||
|
# Get the resource-id of the public ip
|
||||||
|
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)
|
||||||
|
|
||||||
|
# Update public ip address with DNS name
|
||||||
|
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME
|
|
@ -0,0 +1,18 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: tiller
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: tiller
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: cluster-admin
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: tiller
|
||||||
|
namespace: kube-system
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
kubectl create -f helm-rbac.yaml
|
||||||
|
|
||||||
|
helm init --service-account tiller
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
helm install stable/nginx-ingress --namespace kube-system
|
||||||
|
|
||||||
|
echo "Waiting for nginx controller to acquire PUBLIC ip ....."
|
||||||
|
sleep 20
|
||||||
|
###########
|
||||||
|
###HTTPS Controller
|
||||||
|
##########
|
||||||
|
|
||||||
|
IP=`kubectl get service -l app=nginx-ingress --namespace kube-system | sed -n '/controller/s/ \+/ /gp' | cut -d" " -f4`
|
||||||
|
|
||||||
|
echo "INGRESS NGINX public IP is:"
|
||||||
|
echo $IP
|
||||||
|
|
||||||
|
sed -i.bak s/NGINXIP/$IP/g configure-dns.sh
|
||||||
|
|
||||||
|
sed -i.bak1 s/DNSGIVENNAME/$1/g configure-dns.sh
|
||||||
|
|
||||||
|
echo "Configuring DNS ...."
|
||||||
|
sh configure-dns.sh
|
||||||
|
|
||||||
|
mv configure-dns.sh.bak configure-dns.sh
|
||||||
|
|
||||||
|
rm -rf configure-dns.sh.bak1
|
||||||
|
|
||||||
|
echo "Installing cert manager"
|
||||||
|
|
||||||
|
helm install stable/cert-manager --set ingressShim.defaultIssuerName=letsencrypt --set ingressShim.defaultIssuerKind=ClusterIssuer
|
||||||
|
|
||||||
|
echo "Creating SSL cert issuer in cluster ..."
|
||||||
|
|
||||||
|
kubectl apply -f cluster-issuer.yaml
|
||||||
|
|
||||||
|
sed -i.bak s/DNSGIVENNAME/$1/g certificates.yaml
|
||||||
|
|
||||||
|
sed -i.bak1 s/REGION/$2/g certificates.yaml
|
||||||
|
|
||||||
|
mv certificates.yaml.bak certificates.yaml
|
||||||
|
|
||||||
|
rm -rf certificates.yaml.bak1
|
||||||
|
|
||||||
|
echo "Creating certificates resources ...."
|
||||||
|
|
||||||
|
kubectl apply -f certificates.yaml
|
||||||
|
|
||||||
|
echo "Creating Remote Monitoring Nginx controller"
|
||||||
|
|
||||||
|
sed -i.bak s/DNSGIVENNAME/$1/g rm-ingress.yaml
|
||||||
|
|
||||||
|
sed -i.bak s/REGION/$2/g rm-ingress.yaml
|
||||||
|
|
||||||
|
kubectl apply -f rm-ingress.yaml
|
||||||
|
|
||||||
|
mv rm-ingress.yaml.bak rm-ingress.yaml
|
||||||
|
|
||||||
|
rm -rf rm-ingress.yaml.bak1
|
|
@ -0,0 +1,53 @@
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: rm-ingress
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: nginx
|
||||||
|
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
backend:
|
||||||
|
serviceName: webui
|
||||||
|
servicePort: 10080
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||||
|
secretName: tls-secret
|
||||||
|
rules:
|
||||||
|
- host: DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /storageadapter/(.*)
|
||||||
|
backend:
|
||||||
|
serviceName: storageadapter
|
||||||
|
servicePort: 80
|
||||||
|
- path: /iothubmanager/*
|
||||||
|
backend:
|
||||||
|
serviceName: iothubmanager
|
||||||
|
servicePort: 80
|
||||||
|
- path: /telemetry/*
|
||||||
|
backend:
|
||||||
|
serviceName: devicetelemetry
|
||||||
|
servicePort: 80
|
||||||
|
- path: /devicesimulation/*
|
||||||
|
backend:
|
||||||
|
serviceName: simulation
|
||||||
|
servicePort: 80
|
||||||
|
- path: /config/*
|
||||||
|
backend:
|
||||||
|
serviceName: config
|
||||||
|
servicePort: 80
|
||||||
|
- path: /asamanager/(.*)
|
||||||
|
backend:
|
||||||
|
serviceName: asamanager
|
||||||
|
servicePort: 80
|
||||||
|
- path: /auth/(.*)
|
||||||
|
backend:
|
||||||
|
serviceName: auth
|
||||||
|
servicePort: 80
|
||||||
|
- path: /
|
||||||
|
backend:
|
||||||
|
serviceName: webui
|
||||||
|
servicePort: 10080
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
appVersion: "1.0"
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
name: iothubmanager
|
||||||
|
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "iothubmanager.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get svc -w {{ template "iothubmanager.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "iothubmanager.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "iothubmanager.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl port-forward $POD_NAME 8080:80
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{/* vim: set filetype=mustache: */}}
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "iothubmanager.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "iothubmanager.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||||
|
{{- if contains $name .Release.Name -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "iothubmanager.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,76 @@
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "iothubmanager.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "iothubmanager.name" . }}
|
||||||
|
chart: {{ template "iothubmanager.chart" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "iothubmanager.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "iothubmanager.name" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
annotations:
|
||||||
|
buildID: {{ .Values.buildID }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if not .Values.disableProbes }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 120
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 120
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
{{- end }}
|
||||||
|
env:
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $ref, $values := .Values.secrets }}
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ template "iothubmanager.fullname" $root }}-{{ $ref | lower }}
|
||||||
|
key: {{ $key }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "iothubmanager.fullname" . -}}
|
||||||
|
{{- $servicePort := .Values.service.port -}}
|
||||||
|
{{- $ingressPath := .Values.ingress.path -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "iothubmanager.name" . }}
|
||||||
|
chart: {{ template "iothubmanager.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ . }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: {{ $ingressPath }}
|
||||||
|
backend:
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: http
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $name, $values := .Values.secrets }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ template "iothubmanager.fullname" $root }}-{{ $name | lower }}
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
{{ $key }}: {{ $value | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ template "iothubmanager.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "iothubmanager.name" . }}
|
||||||
|
chart: {{ template "iothubmanager.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.externalPort }}
|
||||||
|
targetPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: {{ template "iothubmanager.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Default values for iothubmanager.
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
fullnameOverride: iothubmanager
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: azureiotpcs/iothub-manager-dotnet
|
||||||
|
tag: testing
|
||||||
|
pullPolicy: Always
|
||||||
|
imagePullSecrets: []
|
||||||
|
# Optionally specify an array of imagePullSecrets.
|
||||||
|
# Secrets must be manually created in the namespace.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||||
|
#
|
||||||
|
# This uses credentials from secret "myRegistryKeySecretName".
|
||||||
|
# - name: myRegistryKeySecretName
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
externalPort: 80
|
||||||
|
internalPort: 9002
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
#annotations:
|
||||||
|
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /iothubmanager
|
||||||
|
hosts:
|
||||||
|
- DNSNAME
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.locam
|
||||||
|
secrets:
|
||||||
|
iothubmanager:
|
||||||
|
PCS_AUTH_WEBSERVICE_URL: PCS_AUTH_WEBSERVICE_URL
|
||||||
|
PCS_IOTHUB_CONNSTRING: PCS_IOTHUB_CONNSTRING
|
||||||
|
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||||
|
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||||
|
# Optionally specify a set of secret objects whose values
|
||||||
|
# will be injected as environment variables by default.
|
||||||
|
# You should add this section to a file like secrets.yaml
|
||||||
|
# that is explicitly NOT committed to source code control
|
||||||
|
# and then include it as part of your helm install step.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||||
|
#
|
||||||
|
# This creates a secret "mysecret" and injects "mypassword"
|
||||||
|
# as the environment variable mysecret_mypassword=password.
|
||||||
|
# mysecret:
|
||||||
|
# mypassword: password
|
||||||
|
resources: {}
|
||||||
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
|
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
appVersion: "1.0"
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
name: reverse-proxy
|
||||||
|
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "reverse-proxy.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get svc -w {{ template "reverse-proxy.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "reverse-proxy.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "reverse-proxy.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl port-forward $POD_NAME 8080:80
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{/* vim: set filetype=mustache: */}}
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "reverse-proxy.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "reverse-proxy.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||||
|
{{- if contains $name .Release.Name -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "reverse-proxy.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,79 @@
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "reverse-proxy.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "reverse-proxy.name" . }}
|
||||||
|
chart: {{ template "reverse-proxy.chart" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "reverse-proxy.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "reverse-proxy.name" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
annotations:
|
||||||
|
buildID: {{ .Values.buildID }}
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: certs-volume
|
||||||
|
configMap:
|
||||||
|
name: cert-config
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: certs-volume
|
||||||
|
mountPath: /app/certs
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 10080
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.probes.enabled }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
{{- end }}
|
||||||
|
env:
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $ref, $values := .Values.secrets }}
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ template "reverse-proxy.fullname" $root }}-{{ $ref | lower }}
|
||||||
|
key: {{ $key }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "reverse-proxy.fullname" . -}}
|
||||||
|
{{- $servicePort := .Values.service.port -}}
|
||||||
|
{{- $ingressPath := .Values.ingress.path -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "reverse-proxy.name" . }}
|
||||||
|
chart: {{ template "reverse-proxy.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ . }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: {{ $ingressPath }}
|
||||||
|
backend:
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: http
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $name, $values := .Values.secrets }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ template "reverse-proxy.fullname" $root }}-{{ $name | lower }}
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
{{ $key }}: {{ $value | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,23 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ template "reverse-proxy.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "reverse-proxy.name" . }}
|
||||||
|
chart: {{ template "reverse-proxy.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.externalPort }}
|
||||||
|
targetPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
- port: {{ .Values.service.externalHttpsPort }}
|
||||||
|
targetPort: {{ .Values.service.internalHttpsPort }}
|
||||||
|
protocol: TCP
|
||||||
|
name: https
|
||||||
|
selector:
|
||||||
|
app: {{ template "reverse-proxy.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Default values for reverse-proxy.
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
fullnameOverride: reverse-proxy
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: azureiotpcs/remote-monitoring-nginx
|
||||||
|
tag: testing
|
||||||
|
pullPolicy: Always
|
||||||
|
imagePullSecrets: []
|
||||||
|
# Optionally specify an array of imagePullSecrets.
|
||||||
|
# Secrets must be manually created in the namespace.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||||
|
#
|
||||||
|
# This uses credentials from secret "myRegistryKeySecretName".
|
||||||
|
# - name: myRegistryKeySecretName
|
||||||
|
#
|
||||||
|
probes:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
internalPort: 80
|
||||||
|
externalPort: 10080
|
||||||
|
internalHttpsPort: 443
|
||||||
|
externalHttpsPort: 10443
|
||||||
|
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
#annotations:
|
||||||
|
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /
|
||||||
|
hosts:
|
||||||
|
- rm-aks-test.eastus.cloudapp.azure.com
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
secrets: {}
|
||||||
|
# Optionally specify a set of secret objects whose values
|
||||||
|
# will be injected as environment variables by default.
|
||||||
|
# You should add this section to a file like secrets.yaml
|
||||||
|
# that is explicitly NOT committed to source code control
|
||||||
|
# and then include it as part of your helm install step.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||||
|
#
|
||||||
|
# This creates a secret "mysecret" and injects "mypassword"
|
||||||
|
# as the environment variable mysecret_mypassword=password.
|
||||||
|
# mysecret:
|
||||||
|
# mypassword: password
|
||||||
|
resources: {}
|
||||||
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
|
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
appVersion: "1.0"
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
name: simulation
|
||||||
|
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "simulation.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get svc -w {{ template "simulation.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "simulation.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "simulation.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl port-forward $POD_NAME 8080:80
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{/* vim: set filetype=mustache: */}}
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "simulation.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "simulation.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||||
|
{{- if contains $name .Release.Name -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "simulation.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,79 @@
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "simulation.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "simulation.name" . }}
|
||||||
|
chart: {{ template "simulation.chart" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "simulation.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "simulation.name" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
annotations:
|
||||||
|
buildID: {{ .Values.buildID }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.probes.enabled }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 600
|
||||||
|
timeoutSeconds: 10
|
||||||
|
successThreshold: 5
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 600
|
||||||
|
timeoutSeconds: 10
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
{{- end }}
|
||||||
|
env:
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $ref, $values := .Values.secrets }}
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ template "simulation.fullname" $root }}-{{ $ref | lower }}
|
||||||
|
key: {{ $key }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "simulation.fullname" . -}}
|
||||||
|
{{- $servicePort := .Values.service.port -}}
|
||||||
|
{{- $ingressPath := .Values.ingress.path -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "simulation.name" . }}
|
||||||
|
chart: {{ template "simulation.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ . }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: {{ $ingressPath }}
|
||||||
|
backend:
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: http
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $name, $values := .Values.secrets }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ template "simulation.fullname" $root }}-{{ $name | lower }}
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
{{ $key }}: {{ $value | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ template "simulation.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "simulation.name" . }}
|
||||||
|
chart: {{ template "simulation.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.externalPort }}
|
||||||
|
targetPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: {{ template "simulation.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Default values for simulation.
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
fullnameOverride: simulation
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: azureiotpcs/device-simulation-dotnet
|
||||||
|
tag: DS-1.0.2
|
||||||
|
pullPolicy: Always
|
||||||
|
imagePullSecrets: []
|
||||||
|
# Optionally specify an array of imagePullSecrets.
|
||||||
|
# Secrets must be manually created in the namespace.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||||
|
#
|
||||||
|
# This uses credentials from secret "myRegistryKeySecretName".
|
||||||
|
# - name: myRegistryKeySecretName
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
externalPort: 80
|
||||||
|
internalPort: 9003
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
#annotations:
|
||||||
|
#kubernetes.io/ingress.class: addon-http-application-routing
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /simulation
|
||||||
|
hosts:
|
||||||
|
- DNSNAME
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
secrets:
|
||||||
|
simulation:
|
||||||
|
PCS_IOTHUB_CONNSTRING: PCS_IOTHUB_CONNSTRING
|
||||||
|
PCS_STORAGEADAPTER_WEBSERVICE_URL: PCS_STORAGEADAPTER_WEBSERVICE_URL
|
||||||
|
PCS_AUTH_REQUIRED: PCS_AUTH_REQUIRED
|
||||||
|
# Optionally specify a set of secret objects whose values
|
||||||
|
# will be injected as environment variables by default.
|
||||||
|
# You should add this section to a file like secrets.yaml
|
||||||
|
# that is explicitly NOT committed to source code control
|
||||||
|
# and then include it as part of your helm install step.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||||
|
#
|
||||||
|
# This creates a secret "mysecret" and injects "mypassword"
|
||||||
|
# as the environment variable mysecret_mypassword=password.
|
||||||
|
# mysecret:
|
||||||
|
# mypassword: password
|
||||||
|
resources: {}
|
||||||
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
|
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
#
|
||||||
|
probes:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
appVersion: "1.0"
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
name: storageadapter
|
||||||
|
version: 0.1.0
|
|
@ -0,0 +1,19 @@
|
||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "storageadapter.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get svc -w {{ template "storageadapter.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "storageadapter.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "storageadapter.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl port-forward $POD_NAME 8080:80
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{/* vim: set filetype=mustache: */}}
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "storageadapter.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "storageadapter.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||||
|
{{- if contains $name .Release.Name -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "storageadapter.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,77 @@
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "storageadapter.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "storageadapter.name" . }}
|
||||||
|
chart: {{ template "storageadapter.chart" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "storageadapter.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "storageadapter.name" . }}
|
||||||
|
draft: {{ default "draft-app" .Values.draft }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
annotations:
|
||||||
|
buildID: {{ .Values.buildID }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.internalPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if not .Values.disableProbes }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 120
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /v1/status
|
||||||
|
port: http
|
||||||
|
periodSeconds: 120
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
{{- end }}
|
||||||
|
env:
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $ref, $values := .Values.secrets }}
|
||||||
|
{{- range $key, $value := $values }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ template "storageadapter.fullname" $root }}-{{ $ref | lower }}
|
||||||
|
key: {{ $key }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "storageadapter.fullname" . -}}
|
||||||
|
{{- $servicePort := .Values.service.externalPort -}}
|
||||||
|
{{- $ingressPath := .Values.ingress.path -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "storageadapter.name" . }}
|
||||||
|
chart: {{ template "storageadapter.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ . }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: {{ $ingressPath }}
|
||||||
|
backend:
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: {{ $servicePort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче