Compare commits

..

23 Commits

Author SHA1 Message Date
48a1d6f984 Migrate to json deserializer 2024-01-11 16:18:39 -08:00
79090e91d6 Remove newtonsoft reference 2024-01-11 16:12:55 -08:00
7d2d27c609 Add docker support 2024-01-11 16:10:52 -08:00
c32f3596ec Update launch settings 2024-01-11 16:10:42 -08:00
1fd587634b Add initial docker support 2024-01-11 16:10:17 -08:00
4c17c375ae Remove NewtonSoft Json depedency 2024-01-08 23:45:16 -08:00
bf38c7dc1a Move away from NewtonSoft.Json 2024-01-08 23:28:35 -08:00
afb2102702 Upgrade to .NET 8.0 2024-01-08 22:03:15 -08:00
9c80ad14f3 Update code to properly format the AS Tags 2023-06-14 13:07:02 -07:00
7b6794e7e9 Change from Forbid to NotFound 2023-01-08 15:39:00 -08:00
e3f093b53a Mark types explicitly 2023-01-08 15:35:19 -08:00
5f18fe037c Update the readme file 2023-01-08 15:32:07 -08:00
ab2793d92a Return 403 instead of the view if we can’t get a response out of netbox 2023-01-08 15:07:13 -08:00
9fdc60ac48 Remove unused code 2023-01-08 13:38:47 -08:00
bd8198be2a Unify the strurcture 2023-01-08 13:37:30 -08:00
77e6235b30 Upgrade to .NET 7.0 2023-01-08 13:37:27 -08:00
fc432698a8 Add trailing slash for API endpoint 2023-01-08 13:37:23 -08:00
db29ac0891 Set response cache to an hour 2023-01-08 13:37:19 -08:00
672e56d0aa More cleanup 2023-01-08 13:37:17 -08:00
9311ba2b59 Fix the names 2023-01-08 13:37:15 -08:00
dbccb586f8 Remove unecessary usings 2023-01-08 13:36:46 -08:00
58576796c2 Clean up unused code 2023-01-08 13:36:44 -08:00
1a3450f6f9 Baby steps on code refactoring 2023-01-08 13:36:39 -08:00
14 changed files with 316 additions and 59 deletions

30
.dockerignore Normal file
View File

@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**

View File

@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="System.Text.Json" Version="6.0.7" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
</ItemGroup>
</Project>

View File

@@ -1,63 +1,40 @@
using AS1024.CommunityDocumentationPage.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using AS1024.CommunityDocumentationPage.Interfaces;
namespace AS1024.CommunityDocumentationPage.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private IConfiguration Configuration { get; }
private readonly IBgpCommunity _bgpCommunity;
private readonly IConfiguration _configuration;
public HomeController(ILogger<HomeController> logger,
IConfiguration configuration)
IConfiguration configuration,
IBgpCommunity bgpCommunity)
{
_logger = logger;
Configuration = configuration;
_configuration = configuration;
_bgpCommunity = bgpCommunity;
}
public async Task<IActionResult> IndexAsync()
{
var results = await ReadAPI(Configuration["APIKey"]);
var filtered = results.Results.Where(b => b.Name.StartsWith(Configuration["ASN"]))
.ToList();
return View(filtered);
}
[NonAction]
private async Task<RouteTargets> ReadAPI(string token)
[ResponseCache(Duration = 3600)]
public async Task<IActionResult> Index()
{
try
{
HttpClient client = new();
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", token);
var result = await client.GetAsync(BuildNetBoxURI());
var stringResult = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<RouteTargets>(stringResult);
} catch
var result =
await _bgpCommunity.GetCommunities();
return View(result);
} catch (Exception ex)
{
throw new Exception("Something went wrong?");
_logger.LogError($"Failed to obtain data\n{ex}");
}
}
[NonAction]
protected Uri BuildNetBoxURI()
{
var endUrl = new UriBuilder();
endUrl.Path = "/api/ipam/route-targets";
endUrl.Host = Configuration["NetBoxHost"];
endUrl.Scheme = "https";
return endUrl.Uri;
return NotFound();
}
public IActionResult Privacy()

View File

@@ -0,0 +1,59 @@
using AS1024.CommunityDocumentationPage.Interfaces;
using AS1024.CommunityDocumentationPage.Models;
using System.Text.Json;
using System.Net.Http.Headers;
namespace AS1024.CommunityDocumentationPage.DIScopes
{
public class NetBoxBgpCommunities : IBgpCommunity
{
protected readonly IConfiguration _configuration;
public NetBoxBgpCommunities(IConfiguration configuration)
{
_configuration = configuration;
}
string IBgpCommunity.DcimName => "netbox";
public async Task<ICollection<CommunityTag>> GetCommunities()
{
var Tags = new List<CommunityTag>();
using HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", _configuration["APIKey"]);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage result = await client.GetAsync(BuildNetBoxURI());
string stringResult = await result.Content.ReadAsStringAsync();
var temp =
JsonSerializer.Deserialize<RouteTargets>(stringResult, new JsonSerializerOptions{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
});
foreach (var route in temp.Results)
{
var community = new CommunityTag
{
ASN = int.Parse(route.Name.Split(':')[0]),
CommunityValue = int.Parse(route.Name.Split(':')[1]),
Description = route.Description,
Tag = route.Tags
};
Tags.Add(community);
}
return Tags.OrderBy(b => b.ASN)
.ThenBy(b => b.CommunityValue)
.ToList();
}
protected Uri BuildNetBoxURI()
{
UriBuilder endUrl = new UriBuilder
{
Path = "/api/ipam/route-targets/",
Host = _configuration["NetBoxHost"],
Scheme = "https"
};
return endUrl.Uri;
}
}
}

View File

@@ -0,0 +1,43 @@
using AS1024.CommunityDocumentationPage.Interfaces;
using AS1024.CommunityDocumentationPage.Models;
using System.Net.Http.Headers;
using System.Text.Json;
namespace AS1024.CommunityDocumentationPage.DIScopes
{
public class NetboxBgpCommunityDocumentation : IBgpCommunityDocumentation
{
private readonly IConfiguration configuration;
public string DcimName => "netbox";
public NetboxBgpCommunityDocumentation(IConfiguration configuration)
{
this.configuration = configuration;
}
public async Task<RouteTargets> GetBgpCommunities()
{
using HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", configuration["APIKey"]);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage result = await client.GetAsync(BuildNetBoxURI());
string stringResult = await result.Content.ReadAsStringAsync();
#pragma warning disable CS8603 // Possible null reference return.
return JsonSerializer.Deserialize<RouteTargets>(stringResult,
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower });
#pragma warning restore CS8603 // Possible null reference return.
}
protected Uri BuildNetBoxURI()
{
UriBuilder endUrl = new UriBuilder
{
Path = "/api/ipam/route-targets/",
Host = configuration["NetBoxHost"],
Scheme = "https"
};
return endUrl.Uri;
}
}
}

View File

@@ -0,0 +1,26 @@
namespace AS1024.CommunityDocumentationPage.DIScopes
{
public static class ValidateBgpCommunity
{
/// <summary>
/// validates if this is a valid standard BGP Community
/// </summary>
/// <param name="Community">Community string represented as NNN:XXX</param>
/// <returns>true if it's a valid bgp community, false if it isn't</returns>
public static bool IsValidBgpCommunity(this string Community)
{
string[] splitStrings =
Community.Split(":", StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < 1; i++)
{
if (!int.TryParse(splitStrings[i], out int communityParsed)
&& communityParsed > 65536)
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,26 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
ARG TARGETARCH
WORKDIR /src
COPY ["AS1024.CommunityDocumentationPage/AS1024.CommunityDocumentationPage.csproj", "AS1024.CommunityDocumentationPage/"]
RUN dotnet restore "./AS1024.CommunityDocumentationPage/./AS1024.CommunityDocumentationPage.csproj" -a $TARGETARCH
COPY . .
WORKDIR "/src/AS1024.CommunityDocumentationPage"
RUN dotnet build "./AS1024.CommunityDocumentationPage.csproj" -c $BUILD_CONFIGURATION -o /app/build -a $TARGETARCH
FROM --platform=$BUILDPLATFORM build AS publish
ARG BUILD_CONFIGURATION=Release
ARG TARGETARCH
RUN dotnet publish "./AS1024.CommunityDocumentationPage.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false -a $TARGETARCH
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AS1024.CommunityDocumentationPage.dll"]

View File

@@ -0,0 +1,35 @@
using AS1024.CommunityDocumentationPage.Models;
namespace AS1024.CommunityDocumentationPage.Interfaces
{
/// <summary>
/// Abstraction layer on obtaining BGP communities regardless of DCIM system
/// </summary>
public interface IBgpCommunityDocumentation
{
/// <summary>
/// Read Only field on what the constructor grabs it's data from
/// </summary>
string DcimName { get; }
/// <summary>
/// Gets a list of BGP Communities
/// </summary>
/// <returns></returns>
Task<RouteTargets> GetBgpCommunities();
}
/// <summary>
///
/// </summary>
public interface IBgpCommunity
{
/// <summary>
///
/// </summary>
string DcimName { get; }
/// <summary>
///
/// </summary>
/// <returns></returns>
Task<ICollection<CommunityTag>> GetCommunities();
}
}

View File

@@ -0,0 +1,37 @@
namespace AS1024.CommunityDocumentationPage.Models
{
/// <summary>
///
/// </summary>
public class BgpCommunity
{
/// <summary>
/// Community Tag
/// </summary>
public string CommunityTag { get; set; }
/// <summary>
/// Type of BGP Community
/// </summary>
public CommunityType BgpCommunityType { get; set; }
/// <summary>
/// What the community does
/// </summary>
public string CommunityDescription { get; set; }
}
public enum CommunityType
{
/// <summary>
/// 32 bit community
/// </summary>
Community,
/// <summary>
/// Extended community with RT
/// </summary>
ExtendedCommunity,
/// <summary>
/// Large BGP Community
/// </summary>
LargeCommunity
}
}

View File

@@ -35,4 +35,13 @@
public string slug { get; set; }
public string color { get; set; }
}
public class CommunityTag
{
public int ASN { get; set; }
public int CommunityValue { get; set; }
public string FormattedVaule => $"{this.ASN}:{this.CommunityValue}";
public string? Description { get; set; }
public IList<Tag>? Tag { get; set; }
}
}

View File

@@ -1,8 +1,14 @@
using AS1024.CommunityDocumentationPage.DIScopes;
using AS1024.CommunityDocumentationPage.Interfaces;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddTransient<IBgpCommunityDocumentation, NetboxBgpCommunityDocumentation>();
builder.Services.AddTransient<IBgpCommunity, NetBoxBgpCommunities>();
var app = builder.Build();
// Configure the HTTP request pipeline.

View File

@@ -1,21 +1,12 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49374",
"sslPort": 0
}
},
{
"profiles": {
"AS1024.CommunityDocumentationPage": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5224",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"applicationUrl": "http://localhost:5224"
},
"IIS Express": {
"commandName": "IISExpress",
@@ -23,6 +14,23 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
"environmentVariables": {
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true
}
},
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49374",
"sslPort": 0
}
}
}
}

View File

@@ -1,6 +1,6 @@
@using Microsoft.Extensions.DependencyInjection
@inject IConfiguration Configuration
@model List<AS1024.CommunityDocumentationPage.Models.Result>
@model List<AS1024.CommunityDocumentationPage.Models.CommunityTag>
@{
ViewData["Title"] = "BGP Communities";
}
@@ -20,10 +20,10 @@
</thead>
@foreach (var item in Model) {
<tr>
<td scope="row">@item.Name</td>
<td scope="row">@item.FormattedVaule</td>
<td scope="row">@item.Description</td>
<td scope="row">
@foreach (var tags in item.Tags) {
@foreach (var tags in item.Tag) {
<div class="d-inline-flex p-2 text-white" style="background-color:#@tags.color">@tags.display</div>
}
</td>

View File

@@ -26,4 +26,5 @@ This web app must be configured with asppsettings.json with the following values
- ``APIKey`` - This is a netbox API Key. We strongly recommend that you do this as a read only thing
- ``ASN`` - This is required, without it, the AS's will not display properly
- ``NOCEmail`` - This is to display for NOC E-Mail Inquries
- ``NOCEmail`` - This is to display for NOC E-Mail Inquries
- ``NetBoxHostname`` - The hostname to communicate to the netbox instance - This always assumes your netbox instance is secured by TLS running on port 443