2026-01-19-nah9 #6
121
.gitea/workflows/ci.yaml
Normal file
121
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
name: CI/CD Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build and Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET SDK
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Restore dependencies
|
||||||
|
run: dotnet restore
|
||||||
|
|
||||||
|
- name: Build class library
|
||||||
|
run: dotnet build classlib/classlib.csproj --configuration Release --no-restore
|
||||||
|
|
||||||
|
- name: Build test project
|
||||||
|
run: dotnet build classlib.tests/classlib.tests.csproj --configuration Release --no-restore
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: dotnet test classlib.tests/classlib.tests.csproj --configuration Release --no-build --verbosity normal --logger "trx;LogFileName=test-results.trx" --collect:"XPlat Code Coverage"
|
||||||
|
|
||||||
|
- name: Upload test results
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: test-results
|
||||||
|
path: classlib.tests/TestResults/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
package:
|
||||||
|
name: Package Module
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET SDK
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Build Release
|
||||||
|
run: dotnet build classlib/classlib.csproj --configuration Release
|
||||||
|
|
||||||
|
- name: Create module package
|
||||||
|
run: |
|
||||||
|
mkdir -p output/ps.ipam
|
||||||
|
|
||||||
|
# Copy compiled DLL
|
||||||
|
cp classlib/bin/Release/netstandard2.1/ps.ipam.dll output/ps.ipam/
|
||||||
|
|
||||||
|
# Copy module manifest and related files
|
||||||
|
cp ps.ipam.psd1 output/ps.ipam/
|
||||||
|
cp ps.ipam.psm1 output/ps.ipam/
|
||||||
|
cp LICENSE output/ps.ipam/
|
||||||
|
cp README.md output/ps.ipam/
|
||||||
|
|
||||||
|
# Copy types directory
|
||||||
|
cp -r types output/ps.ipam/
|
||||||
|
|
||||||
|
# Copy functions directory
|
||||||
|
cp -r functions output/ps.ipam/
|
||||||
|
|
||||||
|
# Copy images directory
|
||||||
|
cp -r images output/ps.ipam/
|
||||||
|
|
||||||
|
- name: Upload module artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ps.ipam-module
|
||||||
|
path: output/ps.ipam/
|
||||||
|
retention-days: 90
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Create Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: package
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
steps:
|
||||||
|
- name: Download module artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ps.ipam-module
|
||||||
|
path: ps.ipam
|
||||||
|
|
||||||
|
- name: Create release archive
|
||||||
|
run: |
|
||||||
|
zip -r ps.ipam-${{ github.ref_name }}.zip ps.ipam/
|
||||||
|
tar -czvf ps.ipam-${{ github.ref_name }}.tar.gz ps.ipam/
|
||||||
|
|
||||||
|
- name: Create Gitea Release
|
||||||
|
uses: actions/gitea-release-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.TOKEN }}
|
||||||
|
files: |
|
||||||
|
ps.ipam-${{ github.ref_name }}.zip
|
||||||
|
ps.ipam-${{ github.ref_name }}.tar.gz
|
||||||
|
title: Release ${{ github.ref_name }}
|
||||||
|
draft: false
|
||||||
|
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||||
21
Jenkinsfile
vendored
21
Jenkinsfile
vendored
@@ -1,21 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent {
|
|
||||||
label '.net7.0'
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Build classlib') {
|
|
||||||
steps {
|
|
||||||
sh '''cd classlib
|
|
||||||
dotnet build --no-incremental --force --configuration Release
|
|
||||||
dotnet publish -c Release'''
|
|
||||||
|
|
||||||
contentReplace(configs: [fileContentReplaceConfig(configs: [fileContentReplaceItemConfig(replace: 'ModuleVersion = \'2.0.$BUILD_NUMBER\'', search: 'ModuleVersion = \'2.0\'')], fileEncoding: 'UTF-8', filePath: 'ps.ipam.psd1')])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
success {
|
|
||||||
archiveArtifacts artifacts: 'classlib/bin/Release/netstandard2.1/publish/*.dll, *.psd1, *.psm1, LICENSE, **/*.ps1xml, **/*.ps1', followSymlinks: false, onlyIfSuccessful: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
323
classlib.tests/Cmdlets/GetAddressCmdletTests.cs
Normal file
323
classlib.tests/Cmdlets/GetAddressCmdletTests.cs
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
namespace PS.IPAM.Tests.Cmdlets;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Cmdlets;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
using PS.IPAM.Tests.Mocks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests for the GetAddressCmdlet.
|
||||||
|
/// Note: Full cmdlet testing with parameter sets requires a PowerShell runspace.
|
||||||
|
/// These tests focus on verifying the cmdlet structure and the underlying RequestHelper functionality.
|
||||||
|
/// </summary>
|
||||||
|
[Collection("Sequential")]
|
||||||
|
public class GetAddressCmdletTests : IDisposable
|
||||||
|
{
|
||||||
|
private MockHttpMessageHandler? _mockHandler;
|
||||||
|
|
||||||
|
public GetAddressCmdletTests()
|
||||||
|
{
|
||||||
|
// Clean state before each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
RequestHelper.TestHttpHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Clean up after each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
RequestHelper.TestHttpHandler = null;
|
||||||
|
_mockHandler?.ForceDispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupSession()
|
||||||
|
{
|
||||||
|
SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MockHttpMessageHandler SetupMockHandler()
|
||||||
|
{
|
||||||
|
_mockHandler = new MockHttpMessageHandler();
|
||||||
|
RequestHelper.TestHttpHandler = _mockHandler;
|
||||||
|
return _mockHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_Exists()
|
||||||
|
{
|
||||||
|
// Verify the cmdlet class exists and can be instantiated
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_IdProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.Id = 42;
|
||||||
|
cmdlet.Id.Should().Be(42);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_IPProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.IP = IPAddress.Parse("192.168.1.100");
|
||||||
|
cmdlet.IP.Should().Be(IPAddress.Parse("192.168.1.100"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_HostNameProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.HostName = "server01.example.com";
|
||||||
|
cmdlet.HostName.Should().Be("server01.example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_HostBaseProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.HostBase = "server";
|
||||||
|
cmdlet.HostBase.Should().Be("server");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_TagIdProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.TagId = 2;
|
||||||
|
cmdlet.TagId.Should().Be(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_SubnetIdProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.SubnetId = 10;
|
||||||
|
cmdlet.SubnetId.Should().Be(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetAddressCmdlet_SubnetCIDRProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new GetAddressCmdlet();
|
||||||
|
cmdlet.SubnetCIDR = "192.168.1.0/24";
|
||||||
|
cmdlet.SubnetCIDR.Should().Be("192.168.1.0/24");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the underlying RequestHelper functionality that the cmdlet uses
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_GetAddressById_ReturnsAddress()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var addressJson = @"{
|
||||||
|
""id"": 1,
|
||||||
|
""subnetId"": 10,
|
||||||
|
""ip"": ""192.168.1.100"",
|
||||||
|
""hostname"": ""server01"",
|
||||||
|
""description"": ""Test server""
|
||||||
|
}";
|
||||||
|
handler.WithSuccessResponse(addressJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "1" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeOfType<Address>();
|
||||||
|
var address = (Address)result!;
|
||||||
|
address.Id.Should().Be(1);
|
||||||
|
address.Ip.Should().Be("192.168.1.100");
|
||||||
|
address.Hostname.Should().Be("server01");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_GetAddressById_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"{""id"": 42, ""ip"": ""10.0.0.1""}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "42" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/42/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_SearchByIP_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"{""id"": 1, ""ip"": ""192.168.1.50""}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "search", "192.168.1.50" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/search/192.168.1.50/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_SearchByHostname_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"{""id"": 1, ""ip"": ""10.0.0.5"", ""hostname"": ""myserver.example.com""}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "search_hostname", "myserver.example.com" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/search_hostname/myserver.example.com/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_GetSubnetAddresses_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"[{""id"": 1, ""ip"": ""192.168.1.1""}]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.subnets,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "10", "addresses" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/10/addresses/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_GetAddressesByTag_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"[{""id"": 1, ""ip"": ""10.0.0.1"", ""tag"": 2}]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "tags", "2", "addresses" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/tags/2/addresses/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_ReturnsMultipleAddresses()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"[
|
||||||
|
{""id"": 1, ""ip"": ""192.168.1.1""},
|
||||||
|
{""id"": 2, ""ip"": ""192.168.1.2""},
|
||||||
|
{""id"": 3, ""ip"": ""192.168.1.3""}
|
||||||
|
]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.subnets,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "10", "addresses" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeAssignableTo<System.Collections.IEnumerable>();
|
||||||
|
var addresses = ((System.Collections.IEnumerable)result!).Cast<object>().ToList();
|
||||||
|
addresses.Should().HaveCount(3);
|
||||||
|
addresses.Should().AllBeOfType<Address>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_With404Response_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithNotFoundResponse();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new[] { "999" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestHelper_WithNoSession_ThrowsException()
|
||||||
|
{
|
||||||
|
// Arrange - no session set up
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var action = async () => await RequestHelper.InvokeRequest(
|
||||||
|
"GET",
|
||||||
|
controllers.addresses,
|
||||||
|
types.Address
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await action.Should().ThrowAsync<Exception>().WithMessage("No session available!");
|
||||||
|
}
|
||||||
|
}
|
||||||
103
classlib.tests/Cmdlets/NewSessionCmdletTests.cs
Normal file
103
classlib.tests/Cmdlets/NewSessionCmdletTests.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
namespace PS.IPAM.Tests.Cmdlets;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Cmdlets;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests for the NewSessionCmdlet.
|
||||||
|
/// Note: Full cmdlet testing with parameter sets requires a PowerShell runspace.
|
||||||
|
/// These tests focus on verifying the cmdlet structure and basic functionality.
|
||||||
|
/// </summary>
|
||||||
|
[Collection("Sequential")]
|
||||||
|
public class NewSessionCmdletTests : IDisposable
|
||||||
|
{
|
||||||
|
public NewSessionCmdletTests()
|
||||||
|
{
|
||||||
|
// Clean state before each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Clean up after each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewSessionCmdlet_Exists()
|
||||||
|
{
|
||||||
|
// Verify the cmdlet class exists and can be instantiated
|
||||||
|
var cmdlet = new NewSessionCmdlet();
|
||||||
|
cmdlet.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewSessionCmdlet_URLProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new NewSessionCmdlet();
|
||||||
|
cmdlet.URL = "https://ipam.example.com";
|
||||||
|
cmdlet.URL.Should().Be("https://ipam.example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewSessionCmdlet_AppIDProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new NewSessionCmdlet();
|
||||||
|
cmdlet.AppID = "testapp";
|
||||||
|
cmdlet.AppID.Should().Be("testapp");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewSessionCmdlet_TokenProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new NewSessionCmdlet();
|
||||||
|
cmdlet.Token = "my-api-token";
|
||||||
|
cmdlet.Token.Should().Be("my-api-token");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewSessionCmdlet_CredentialsProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new NewSessionCmdlet();
|
||||||
|
cmdlet.Credentials = null;
|
||||||
|
cmdlet.Credentials.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NewSessionCmdlet_IgnoreSSLProperty_Exists()
|
||||||
|
{
|
||||||
|
var cmdlet = new NewSessionCmdlet();
|
||||||
|
// SwitchParameter defaults to false
|
||||||
|
cmdlet.IgnoreSSL.IsPresent.Should().BeFalse();
|
||||||
|
// Setting it to true
|
||||||
|
var switchParam = new System.Management.Automation.SwitchParameter(true);
|
||||||
|
cmdlet.IgnoreSSL = switchParam;
|
||||||
|
// Note: SwitchParameter is a struct, so getting the value back may not work as expected
|
||||||
|
// Just verify the property exists and can be set
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SessionManager_CreateSessionWithToken_WorksCorrectly()
|
||||||
|
{
|
||||||
|
// This tests the underlying functionality that the cmdlet uses
|
||||||
|
var session = SessionManager.CreateSessionWithToken(
|
||||||
|
"https://ipam.example.com",
|
||||||
|
"testapp",
|
||||||
|
"my-api-token"
|
||||||
|
);
|
||||||
|
|
||||||
|
session.Should().NotBeNull();
|
||||||
|
session.URL.Should().Be("https://ipam.example.com");
|
||||||
|
session.AppID.Should().Be("testapp");
|
||||||
|
session.Token.Should().Be("my-api-token");
|
||||||
|
session.AuthType.Should().Be(AuthType.token);
|
||||||
|
session.Expires.Should().BeNull();
|
||||||
|
session.Credentials.Should().BeNull();
|
||||||
|
|
||||||
|
// Verify it was set as current session
|
||||||
|
SessionManager.CurrentSession.Should().BeSameAs(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
503
classlib.tests/Helpers/RequestHelperTests.cs
Normal file
503
classlib.tests/Helpers/RequestHelperTests.cs
Normal file
@@ -0,0 +1,503 @@
|
|||||||
|
namespace PS.IPAM.Tests.Helpers;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
using PS.IPAM.Tests.Mocks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
[Collection("Sequential")]
|
||||||
|
public class RequestHelperTests : IDisposable
|
||||||
|
{
|
||||||
|
private MockHttpMessageHandler? _mockHandler;
|
||||||
|
|
||||||
|
public RequestHelperTests()
|
||||||
|
{
|
||||||
|
// Clean state before each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
RequestHelper.TestHttpHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Clean up after each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
RequestHelper.TestHttpHandler = null;
|
||||||
|
_mockHandler?.ForceDispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupSession(AuthType authType = AuthType.token)
|
||||||
|
{
|
||||||
|
if (authType == AuthType.token)
|
||||||
|
{
|
||||||
|
SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For credentials auth, we need to set up a session manually with future expiry
|
||||||
|
var session = new Session(
|
||||||
|
AuthType.credentials,
|
||||||
|
"cred-token",
|
||||||
|
"testapp",
|
||||||
|
"https://ipam.example.com",
|
||||||
|
DateTime.Now.AddHours(1),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
SessionManager.CurrentSession = session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MockHttpMessageHandler SetupMockHandler()
|
||||||
|
{
|
||||||
|
_mockHandler = new MockHttpMessageHandler();
|
||||||
|
RequestHelper.TestHttpHandler = _mockHandler;
|
||||||
|
return _mockHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithNoSession_ThrowsException()
|
||||||
|
{
|
||||||
|
// Arrange - no session set up
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var action = async () => await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await action.Should().ThrowAsync<Exception>().WithMessage("No session available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithValidSession_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{\"id\":1,\"ip\":\"192.168.1.1\"}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest.Should().NotBeNull();
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Be("https://ipam.example.com/api/testapp/addresses/1/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithSubController_BuildsCorrectUri()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("[]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("GET", controllers.subnets, null, subcontrollers.tags, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/tags/1/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithTokenAuth_AddsPhpipamTokenHeader()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession(AuthType.token);
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.GetLastRequestHeader("phpipam-token").Should().Be("test-token");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithCredentialsAuth_AddsTokenHeader()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession(AuthType.credentials);
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.GetLastRequestHeader("token").Should().Be("cred-token");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_GetMethod_UsesHttpGet()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.Method.Should().Be(HttpMethod.Get);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_PostMethod_UsesHttpPost()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{\"id\":1}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, new { ip = "10.0.0.1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.Method.Should().Be(HttpMethod.Post);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_PatchMethod_UsesHttpPatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{\"id\":1}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, new { description = "updated" }, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.Method.Should().Be(new HttpMethod("PATCH"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_DeleteMethod_UsesHttpDelete()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("DELETE", controllers.addresses, null, null, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.Method.Should().Be(HttpMethod.Delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_With404Response_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithNotFoundResponse();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "999" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithErrorResponse_ThrowsHttpRequestException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithErrorResponse(HttpStatusCode.InternalServerError, "Server error");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var action = async () => await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await action.Should().ThrowAsync<HttpRequestException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithAddressType_ReturnsAddressObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var addressJson = @"{
|
||||||
|
""id"": 1,
|
||||||
|
""subnetId"": 10,
|
||||||
|
""ip"": ""192.168.1.100"",
|
||||||
|
""is_gateway"": false,
|
||||||
|
""description"": ""Test server"",
|
||||||
|
""hostname"": ""server01"",
|
||||||
|
""mac"": ""00:11:22:33:44:55"",
|
||||||
|
""owner"": ""admin"",
|
||||||
|
""tag"": 2,
|
||||||
|
""deviceId"": 0,
|
||||||
|
""location"": """",
|
||||||
|
""port"": """",
|
||||||
|
""note"": """",
|
||||||
|
""lastSeen"": null,
|
||||||
|
""excludePing"": false,
|
||||||
|
""PTRignore"": false,
|
||||||
|
""PTR"": 0,
|
||||||
|
""firewallAddressObject"": """",
|
||||||
|
""editDate"": null,
|
||||||
|
""customer_id"": 0
|
||||||
|
}";
|
||||||
|
handler.WithSuccessResponse(addressJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeOfType<Address>();
|
||||||
|
var address = (Address)result!;
|
||||||
|
address.Id.Should().Be(1);
|
||||||
|
address.Ip.Should().Be("192.168.1.100");
|
||||||
|
address.Hostname.Should().Be("server01");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithAddressArray_ReturnsListOfAddresses()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var addressArrayJson = @"[
|
||||||
|
{""id"": 1, ""subnetId"": 10, ""ip"": ""192.168.1.1"", ""hostname"": ""host1""},
|
||||||
|
{""id"": 2, ""subnetId"": 10, ""ip"": ""192.168.1.2"", ""hostname"": ""host2""}
|
||||||
|
]";
|
||||||
|
handler.WithSuccessResponse(addressArrayJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.subnets, types.Address, null, null, new[] { "10", "addresses" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeAssignableTo<IEnumerable<object>>();
|
||||||
|
var addresses = ((IEnumerable<object>)result!).ToList();
|
||||||
|
addresses.Should().HaveCount(2);
|
||||||
|
addresses[0].Should().BeOfType<Address>();
|
||||||
|
((Address)addresses[0]).Ip.Should().Be("192.168.1.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithVlanType_ReturnsVlanObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var vlanJson = @"{
|
||||||
|
""vlanId"": 100,
|
||||||
|
""domainId"": 1,
|
||||||
|
""name"": ""Production"",
|
||||||
|
""number"": 100,
|
||||||
|
""description"": ""Production VLAN"",
|
||||||
|
""editDate"": null,
|
||||||
|
""customer_id"": 0
|
||||||
|
}";
|
||||||
|
handler.WithSuccessResponse(vlanJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.vlan, types.Vlan, null, null, new[] { "100" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeOfType<Vlan>();
|
||||||
|
var vlan = (Vlan)result!;
|
||||||
|
vlan.Name.Should().Be("Production");
|
||||||
|
vlan.Number.Should().Be(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithSubnetworkType_ReturnsSubnetworkObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var subnetJson = @"{
|
||||||
|
""id"": 1,
|
||||||
|
""subnet"": ""192.168.1.0"",
|
||||||
|
""mask"": 24,
|
||||||
|
""sectionId"": 1,
|
||||||
|
""description"": ""Test subnet"",
|
||||||
|
""linked_subnet"": """",
|
||||||
|
""firewallAddressObject"": """",
|
||||||
|
""vrfId"": 0,
|
||||||
|
""masterSubnetId"": 0,
|
||||||
|
""allowRequests"": false,
|
||||||
|
""vlanId"": 100,
|
||||||
|
""showName"": false,
|
||||||
|
""deviceId"": 0,
|
||||||
|
""permissions"": """",
|
||||||
|
""pingSubnet"": false,
|
||||||
|
""discoverSubnet"": false,
|
||||||
|
""resolveDNS"": false,
|
||||||
|
""DNSrecursive"": false,
|
||||||
|
""DNSrecords"": false,
|
||||||
|
""nameserverId"": 0,
|
||||||
|
""scanAgent"": false,
|
||||||
|
""isFolder"": false,
|
||||||
|
""isFull"": false,
|
||||||
|
""isPool"": false,
|
||||||
|
""state"": 1,
|
||||||
|
""threshold"": 0,
|
||||||
|
""location"": 0,
|
||||||
|
""editDate"": null,
|
||||||
|
""lastScan"": null,
|
||||||
|
""lastDiscovery"": null,
|
||||||
|
""calculation"": {}
|
||||||
|
}";
|
||||||
|
handler.WithSuccessResponse(subnetJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeOfType<Subnetwork>();
|
||||||
|
var subnet = (Subnetwork)result!;
|
||||||
|
subnet.Subnet.Should().Be("192.168.1.0");
|
||||||
|
subnet.Mask.Should().Be(24);
|
||||||
|
subnet.GetCIDR().Should().Be("192.168.1.0/24");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithSectionType_ReturnsSectionObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var sectionJson = @"{
|
||||||
|
""id"": 1,
|
||||||
|
""name"": ""Production"",
|
||||||
|
""description"": ""Production section"",
|
||||||
|
""masterSection"": 0,
|
||||||
|
""permissions"": """",
|
||||||
|
""strictMode"": false,
|
||||||
|
""subnetOrdering"": ""default"",
|
||||||
|
""order"": 1,
|
||||||
|
""editDate"": null,
|
||||||
|
""showSubnet"": true,
|
||||||
|
""showVlan"": true,
|
||||||
|
""showVRF"": false,
|
||||||
|
""showSupernetOnly"": false,
|
||||||
|
""DNS"": 0
|
||||||
|
}";
|
||||||
|
handler.WithSuccessResponse(sectionJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeOfType<Section>();
|
||||||
|
var section = (Section)result!;
|
||||||
|
section.Name.Should().Be("Production");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithCustomFields_ParsesExtendedData()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
var addressJson = @"{
|
||||||
|
""id"": 1,
|
||||||
|
""subnetId"": 10,
|
||||||
|
""ip"": ""192.168.1.100"",
|
||||||
|
""hostname"": ""server01"",
|
||||||
|
""custom_environment"": ""production"",
|
||||||
|
""custom_owner"": ""team-a""
|
||||||
|
}";
|
||||||
|
handler.WithSuccessResponse(addressJson);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var address = (Address)result!;
|
||||||
|
address.ExtendedData.Should().NotBeNull();
|
||||||
|
var extendedData = (Dictionary<string, object>)address.ExtendedData!;
|
||||||
|
extendedData.Should().ContainKey("custom_environment");
|
||||||
|
extendedData.Should().ContainKey("custom_owner");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithNoType_ReturnsDynamicData()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"{""some"": ""data""}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.tools);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_PostWithParameters_SerializesJsonBody()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse(@"{""id"": 1}");
|
||||||
|
|
||||||
|
var parameters = new { ip = "10.0.0.1", subnetId = 5, description = "New address" };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, parameters);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.Content.Should().NotBeNull();
|
||||||
|
var content = await handler.LastRequest.Content!.ReadAsStringAsync();
|
||||||
|
content.Should().Contain("10.0.0.1");
|
||||||
|
content.Should().Contain("subnetId");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_SetsAcceptJsonHeader()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithSuccessResponse("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handler.LastRequest!.Headers.Accept.Should().Contain(h => h.MediaType == "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithEmptyResponse_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithResponse(HttpStatusCode.OK, "", "application/json");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeRequest_WithNullDataInResponse_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SetupSession();
|
||||||
|
var handler = SetupMockHandler();
|
||||||
|
handler.WithJsonResponse(@"{""code"": 200, ""success"": true, ""data"": null}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
193
classlib.tests/Helpers/SessionManagerTests.cs
Normal file
193
classlib.tests/Helpers/SessionManagerTests.cs
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
namespace PS.IPAM.Tests.Helpers;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
[Collection("Sequential")]
|
||||||
|
public class SessionManagerTests : IDisposable
|
||||||
|
{
|
||||||
|
public SessionManagerTests()
|
||||||
|
{
|
||||||
|
// Ensure clean state before each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Clean up after each test
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestSession_WhenNoSession_ReturnsNoToken()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SessionManager.CurrentSession = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = SessionManager.TestSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("NoToken");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestSession_WhenSessionWithNullExpires_ReturnsValid()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var session = new Session(AuthType.token, "test-token", "app", "https://test.com", null, null);
|
||||||
|
SessionManager.CurrentSession = session;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = SessionManager.TestSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("Valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestSession_WhenSessionNotExpired_ReturnsValid()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var futureExpiry = DateTime.Now.AddHours(1);
|
||||||
|
var session = new Session(AuthType.credentials, "test-token", "app", "https://test.com", futureExpiry, null);
|
||||||
|
SessionManager.CurrentSession = session;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = SessionManager.TestSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("Valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestSession_WhenSessionExpired_ReturnsExpired()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var pastExpiry = DateTime.Now.AddHours(-1);
|
||||||
|
var session = new Session(AuthType.credentials, "test-token", "app", "https://test.com", pastExpiry, null);
|
||||||
|
SessionManager.CurrentSession = session;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = SessionManager.TestSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("Expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateSessionWithToken_CreatesValidSession()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var url = "https://ipam.example.com";
|
||||||
|
var appId = "myApp";
|
||||||
|
var token = "static-api-token";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var session = SessionManager.CreateSessionWithToken(url, appId, token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
session.Should().NotBeNull();
|
||||||
|
session.URL.Should().Be(url);
|
||||||
|
session.AppID.Should().Be(appId);
|
||||||
|
session.Token.Should().Be(token);
|
||||||
|
session.AuthType.Should().Be(AuthType.token);
|
||||||
|
session.Expires.Should().BeNull();
|
||||||
|
session.Credentials.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateSessionWithToken_SetsCurrentSession()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var url = "https://ipam.example.com";
|
||||||
|
var appId = "myApp";
|
||||||
|
var token = "api-token";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var session = SessionManager.CreateSessionWithToken(url, appId, token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
SessionManager.CurrentSession.Should().BeSameAs(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CloseSession_ClearsCurrentSession()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SessionManager.CreateSessionWithToken("https://test.com", "app", "token");
|
||||||
|
SessionManager.CurrentSession.Should().NotBeNull();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
SessionManager.CurrentSession.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CloseSession_WhenNoSession_DoesNotThrow()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SessionManager.CurrentSession = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var action = () => SessionManager.CloseSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().NotThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CurrentSession_CanBeSetDirectly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var session = new Session(AuthType.token, "token", "app", "https://test.com", null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
SessionManager.CurrentSession = session;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
SessionManager.CurrentSession.Should().BeSameAs(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateHttpClient_WithoutIgnoreSsl_ReturnsHttpClient()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
using var client = SessionManager.CreateHttpClient(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
client.Should().NotBeNull();
|
||||||
|
client.Should().BeOfType<HttpClient>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateHttpClient_WithIgnoreSsl_ReturnsHttpClient()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
using var client = SessionManager.CreateHttpClient(true);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
client.Should().NotBeNull();
|
||||||
|
client.Should().BeOfType<HttpClient>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateSessionWithToken_ReplacesExistingSession()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
SessionManager.CreateSessionWithToken("https://old.com", "oldApp", "oldToken");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var newSession = SessionManager.CreateSessionWithToken("https://new.com", "newApp", "newToken");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
SessionManager.CurrentSession.Should().BeSameAs(newSession);
|
||||||
|
SessionManager.CurrentSession!.URL.Should().Be("https://new.com");
|
||||||
|
SessionManager.CurrentSession.AppID.Should().Be("newApp");
|
||||||
|
SessionManager.CurrentSession.Token.Should().Be("newToken");
|
||||||
|
}
|
||||||
|
}
|
||||||
139
classlib.tests/Mocks/CmdletTestHelper.cs
Normal file
139
classlib.tests/Mocks/CmdletTestHelper.cs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
namespace PS.IPAM.Tests.Mocks;
|
||||||
|
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Management.Automation.Host;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper class for testing PowerShell cmdlets.
|
||||||
|
/// </summary>
|
||||||
|
public class CmdletTestHelper<T> : IDisposable where T : PSCmdlet, new()
|
||||||
|
{
|
||||||
|
private readonly T _cmdlet;
|
||||||
|
private readonly List<object> _output = new();
|
||||||
|
private readonly List<ErrorRecord> _errors = new();
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public CmdletTestHelper()
|
||||||
|
{
|
||||||
|
_cmdlet = new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cmdlet instance for setting parameters.
|
||||||
|
/// </summary>
|
||||||
|
public T Cmdlet => _cmdlet;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the output objects written by the cmdlet.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<object> Output => _output.AsReadOnly();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the errors written by the cmdlet.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<ErrorRecord> Errors => _errors.AsReadOnly();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether any errors were written.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasErrors => _errors.Count > 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the cmdlet and captures output.
|
||||||
|
/// </summary>
|
||||||
|
public void Invoke()
|
||||||
|
{
|
||||||
|
// Use reflection to call the protected ProcessRecord method
|
||||||
|
var processMethod = typeof(T).GetMethod("ProcessRecord",
|
||||||
|
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
if (processMethod == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("ProcessRecord method not found on cmdlet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up a mock command runtime to capture output
|
||||||
|
var runtime = new MockCommandRuntime(_output, _errors);
|
||||||
|
var runtimeProperty = typeof(Cmdlet).GetProperty("CommandRuntime",
|
||||||
|
BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
runtimeProperty?.SetValue(_cmdlet, runtime);
|
||||||
|
|
||||||
|
// Invoke the method
|
||||||
|
try
|
||||||
|
{
|
||||||
|
processMethod.Invoke(_cmdlet, null);
|
||||||
|
}
|
||||||
|
catch (TargetInvocationException ex) when (ex.InnerException != null)
|
||||||
|
{
|
||||||
|
// Unwrap the exception
|
||||||
|
throw ex.InnerException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mock implementation of ICommandRuntime for capturing cmdlet output.
|
||||||
|
/// This is a minimal implementation that only handles the methods we need for testing.
|
||||||
|
/// </summary>
|
||||||
|
internal class MockCommandRuntime : ICommandRuntime
|
||||||
|
{
|
||||||
|
private readonly List<object> _output;
|
||||||
|
private readonly List<ErrorRecord> _errors;
|
||||||
|
|
||||||
|
public MockCommandRuntime(List<object> output, List<ErrorRecord> errors)
|
||||||
|
{
|
||||||
|
_output = output;
|
||||||
|
_errors = errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PSHost Host => null!;
|
||||||
|
public PSTransactionContext CurrentPSTransaction => null!;
|
||||||
|
|
||||||
|
public bool ShouldContinue(string query, string caption) => true;
|
||||||
|
public bool ShouldContinue(string query, string caption, ref bool yesToAll, ref bool noToAll) => true;
|
||||||
|
public bool ShouldProcess(string target) => true;
|
||||||
|
public bool ShouldProcess(string target, string action) => true;
|
||||||
|
public bool ShouldProcess(string verboseDescription, string verboseWarning, string caption) => true;
|
||||||
|
public bool ShouldProcess(string verboseDescription, string verboseWarning, string caption, out ShouldProcessReason shouldProcessReason)
|
||||||
|
{
|
||||||
|
shouldProcessReason = ShouldProcessReason.None;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TransactionAvailable() => false;
|
||||||
|
|
||||||
|
public void ThrowTerminatingError(ErrorRecord errorRecord) => throw errorRecord.Exception;
|
||||||
|
|
||||||
|
public void WriteCommandDetail(string text) { }
|
||||||
|
public void WriteDebug(string text) { }
|
||||||
|
public void WriteError(ErrorRecord errorRecord) => _errors.Add(errorRecord);
|
||||||
|
public void WriteObject(object sendToPipeline) => _output.Add(sendToPipeline);
|
||||||
|
public void WriteObject(object sendToPipeline, bool enumerateCollection)
|
||||||
|
{
|
||||||
|
if (enumerateCollection && sendToPipeline is System.Collections.IEnumerable enumerable)
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
_output.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_output.Add(sendToPipeline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void WriteProgress(ProgressRecord progressRecord) { }
|
||||||
|
public void WriteProgress(long sourceId, ProgressRecord progressRecord) { }
|
||||||
|
public void WriteVerbose(string text) { }
|
||||||
|
public void WriteWarning(string text) { }
|
||||||
|
}
|
||||||
172
classlib.tests/Mocks/MockHttpMessageHandler.cs
Normal file
172
classlib.tests/Mocks/MockHttpMessageHandler.cs
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
namespace PS.IPAM.Tests.Mocks;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A mock HTTP message handler for testing HTTP requests without making actual network calls.
|
||||||
|
/// This handler does not dispose itself when the HttpClient is disposed, allowing reuse in tests.
|
||||||
|
/// </summary>
|
||||||
|
public class MockHttpMessageHandler : HttpMessageHandler
|
||||||
|
{
|
||||||
|
private readonly Queue<MockResponse> _responses = new();
|
||||||
|
private readonly List<HttpRequestMessage> _requests = new();
|
||||||
|
private bool _disposed = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all requests that were sent through this handler.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<HttpRequestMessage> Requests => _requests.AsReadOnly();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last request that was sent through this handler.
|
||||||
|
/// </summary>
|
||||||
|
public HttpRequestMessage? LastRequest => _requests.LastOrDefault();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues a response to be returned for the next request.
|
||||||
|
/// </summary>
|
||||||
|
public MockHttpMessageHandler WithResponse(HttpStatusCode statusCode, string content, string contentType = "application/json")
|
||||||
|
{
|
||||||
|
_responses.Enqueue(new MockResponse(statusCode, content, contentType));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues a successful JSON response.
|
||||||
|
/// </summary>
|
||||||
|
public MockHttpMessageHandler WithJsonResponse(string jsonContent)
|
||||||
|
{
|
||||||
|
return WithResponse(HttpStatusCode.OK, jsonContent, "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues a successful response with phpIPAM-style wrapper.
|
||||||
|
/// </summary>
|
||||||
|
public MockHttpMessageHandler WithSuccessResponse(string dataJson)
|
||||||
|
{
|
||||||
|
var response = $"{{\"code\":200,\"success\":true,\"data\":{dataJson}}}";
|
||||||
|
return WithJsonResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues a 404 Not Found response.
|
||||||
|
/// </summary>
|
||||||
|
public MockHttpMessageHandler WithNotFoundResponse()
|
||||||
|
{
|
||||||
|
return WithResponse(HttpStatusCode.NotFound, "{\"code\":404,\"success\":false,\"message\":\"Not found\"}", "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues an error response.
|
||||||
|
/// </summary>
|
||||||
|
public MockHttpMessageHandler WithErrorResponse(HttpStatusCode statusCode, string message)
|
||||||
|
{
|
||||||
|
var response = $"{{\"code\":{(int)statusCode},\"success\":false,\"message\":\"{message}\"}}";
|
||||||
|
return WithResponse(statusCode, response, "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues an exception to be thrown on the next request.
|
||||||
|
/// </summary>
|
||||||
|
public MockHttpMessageHandler WithException(Exception exception)
|
||||||
|
{
|
||||||
|
_responses.Enqueue(new MockResponse(exception));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(MockHttpMessageHandler));
|
||||||
|
}
|
||||||
|
|
||||||
|
_requests.Add(request);
|
||||||
|
|
||||||
|
if (_responses.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("No mock response configured. Call WithResponse() before making requests.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var mockResponse = _responses.Dequeue();
|
||||||
|
|
||||||
|
if (mockResponse.Exception != null)
|
||||||
|
{
|
||||||
|
throw mockResponse.Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = new HttpResponseMessage(mockResponse.StatusCode)
|
||||||
|
{
|
||||||
|
Content = new StringContent(mockResponse.Content, System.Text.Encoding.UTF8, mockResponse.ContentType),
|
||||||
|
RequestMessage = request
|
||||||
|
};
|
||||||
|
|
||||||
|
return Task.FromResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
// Don't actually dispose - allow reuse in tests
|
||||||
|
// The test itself is responsible for cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Actually disposes the handler. Call this in test cleanup.
|
||||||
|
/// </summary>
|
||||||
|
public void ForceDispose()
|
||||||
|
{
|
||||||
|
_disposed = true;
|
||||||
|
base.Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies that a request was made to the expected URL.
|
||||||
|
/// </summary>
|
||||||
|
public bool WasRequestMadeTo(string urlContains)
|
||||||
|
{
|
||||||
|
return _requests.Any(r => r.RequestUri?.ToString().Contains(urlContains) == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies that a request with the expected method was made.
|
||||||
|
/// </summary>
|
||||||
|
public bool WasRequestMadeWithMethod(HttpMethod method)
|
||||||
|
{
|
||||||
|
return _requests.Any(r => r.Method == method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of a header from the last request.
|
||||||
|
/// </summary>
|
||||||
|
public string? GetLastRequestHeader(string headerName)
|
||||||
|
{
|
||||||
|
if (LastRequest?.Headers.TryGetValues(headerName, out var values) == true)
|
||||||
|
{
|
||||||
|
return values.FirstOrDefault();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MockResponse
|
||||||
|
{
|
||||||
|
public HttpStatusCode StatusCode { get; }
|
||||||
|
public string Content { get; }
|
||||||
|
public string ContentType { get; }
|
||||||
|
public Exception? Exception { get; }
|
||||||
|
|
||||||
|
public MockResponse(HttpStatusCode statusCode, string content, string contentType)
|
||||||
|
{
|
||||||
|
StatusCode = statusCode;
|
||||||
|
Content = content;
|
||||||
|
ContentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MockResponse(Exception exception)
|
||||||
|
{
|
||||||
|
Exception = exception;
|
||||||
|
StatusCode = HttpStatusCode.InternalServerError;
|
||||||
|
Content = string.Empty;
|
||||||
|
ContentType = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
classlib.tests/Models/AddressTests.cs
Normal file
116
classlib.tests/Models/AddressTests.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class AddressTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var subnetId = 10;
|
||||||
|
var ip = "192.168.1.100";
|
||||||
|
var isGateway = true;
|
||||||
|
var description = "Test server";
|
||||||
|
var hostname = "server01.example.com";
|
||||||
|
var mac = "00:11:22:33:44:55";
|
||||||
|
var owner = "admin";
|
||||||
|
var tagId = 2;
|
||||||
|
var deviceId = 5;
|
||||||
|
var location = "DC1";
|
||||||
|
var port = "eth0";
|
||||||
|
var note = "Production server";
|
||||||
|
var lastSeen = new DateTime(2026, 1, 15, 10, 30, 0);
|
||||||
|
var excludePing = false;
|
||||||
|
var ptrIgnore = true;
|
||||||
|
var ptr = 1;
|
||||||
|
var firewallObject = "FW_SERVER01";
|
||||||
|
var editDate = new DateTime(2026, 1, 10, 8, 0, 0);
|
||||||
|
var customerId = 100;
|
||||||
|
var extendedData = new Dictionary<string, object> { { "custom_field1", "value1" } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var address = new Address(
|
||||||
|
id, subnetId, ip, isGateway, description, hostname, mac, owner,
|
||||||
|
tagId, deviceId, location, port, note, lastSeen, excludePing,
|
||||||
|
ptrIgnore, ptr, firewallObject, editDate, customerId, extendedData
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
address.Id.Should().Be(id);
|
||||||
|
address.SubnetId.Should().Be(subnetId);
|
||||||
|
address.Ip.Should().Be(ip);
|
||||||
|
address.IsGateway.Should().Be(isGateway);
|
||||||
|
address.Description.Should().Be(description);
|
||||||
|
address.Hostname.Should().Be(hostname);
|
||||||
|
address.MAC.Should().Be(mac);
|
||||||
|
address.Owner.Should().Be(owner);
|
||||||
|
address.TagId.Should().Be(tagId);
|
||||||
|
address.DeviceId.Should().Be(deviceId);
|
||||||
|
address.Location.Should().Be(location);
|
||||||
|
address.Port.Should().Be(port);
|
||||||
|
address.Note.Should().Be(note);
|
||||||
|
address.LastSeen.Should().Be(lastSeen);
|
||||||
|
address.ExcludePing.Should().Be(excludePing);
|
||||||
|
address.PTRignore.Should().Be(ptrIgnore);
|
||||||
|
address.PTR.Should().Be(ptr);
|
||||||
|
address.FirewallAddressObject.Should().Be(firewallObject);
|
||||||
|
address.EditDate.Should().Be(editDate);
|
||||||
|
address.CustomerId.Should().Be(customerId);
|
||||||
|
address.ExtendedData.Should().BeEquivalentTo(extendedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithNullOptionalFields_SetsNullValues()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var address = new Address(
|
||||||
|
1, 10, "10.0.0.1", false, "", "", "", "",
|
||||||
|
0, 0, "", "", "", null, false,
|
||||||
|
false, 0, "", null, 0, null
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
address.LastSeen.Should().BeNull();
|
||||||
|
address.EditDate.Should().BeNull();
|
||||||
|
address.ExtendedData.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToString_ReturnsIpAddress()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var address = new Address(
|
||||||
|
1, 10, "192.168.1.50", false, "Test", "host.local", "", "",
|
||||||
|
0, 0, "", "", "", null, false,
|
||||||
|
false, 0, "", null, 0, null
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = address.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("192.168.1.50");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("10.0.0.1")]
|
||||||
|
[InlineData("172.16.0.100")]
|
||||||
|
[InlineData("192.168.255.255")]
|
||||||
|
[InlineData("2001:db8::1")]
|
||||||
|
public void ToString_ReturnsCorrectIp_ForVariousAddresses(string expectedIp)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var address = new Address(
|
||||||
|
1, 1, expectedIp, false, "", "", "", "",
|
||||||
|
0, 0, "", "", "", null, false,
|
||||||
|
false, 0, "", null, 0, null
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
address.ToString().Should().Be(expectedIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
43
classlib.tests/Models/DomainTests.cs
Normal file
43
classlib.tests/Models/DomainTests.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class DomainTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var name = "Default";
|
||||||
|
var description = "Default L2 domain";
|
||||||
|
var sections = "1;2;3";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var domain = new Domain(id, name, description, sections);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
domain.Id.Should().Be(id);
|
||||||
|
domain.Name.Should().Be(name);
|
||||||
|
domain.Description.Should().Be(description);
|
||||||
|
domain.Sections.Should().Be(sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Default")]
|
||||||
|
[InlineData("Datacenter1")]
|
||||||
|
[InlineData("Branch_Office")]
|
||||||
|
public void ToString_ReturnsDomainName(string domainName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var domain = new Domain(1, domainName, "", "");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = domain.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(domainName);
|
||||||
|
}
|
||||||
|
}
|
||||||
82
classlib.tests/Models/NameserverTests.cs
Normal file
82
classlib.tests/Models/NameserverTests.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class NameserverTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var name = "Google DNS";
|
||||||
|
var nameServers = "8.8.8.8;8.8.4.4";
|
||||||
|
var description = "Google Public DNS";
|
||||||
|
var permissions = "{\"3\":\"2\"}";
|
||||||
|
var editDate = new DateTime(2026, 1, 10);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var nameserver = new Nameserver(id, name, nameServers, description, permissions, editDate);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
nameserver.Id.Should().Be(id);
|
||||||
|
nameserver.Name.Should().Be(name);
|
||||||
|
nameserver.Description.Should().Be(description);
|
||||||
|
nameserver.Permissions.Should().Be(permissions);
|
||||||
|
nameserver.EditDate.Should().Be(editDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_ParsesNameservers_BySemicolon()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var nameServersString = "8.8.8.8;8.8.4.4;1.1.1.1";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
nameserver.NameServers.Should().HaveCount(3);
|
||||||
|
nameserver.NameServers.Should().ContainInOrder("8.8.8.8", "8.8.4.4", "1.1.1.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithSingleNameserver_ReturnsArrayWithOneElement()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var nameServersString = "8.8.8.8";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
nameserver.NameServers.Should().HaveCount(1);
|
||||||
|
nameserver.NameServers[0].Should().Be("8.8.8.8");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithEmptyNameservers_ReturnsArrayWithEmptyString()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var nameServersString = "";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
nameserver.NameServers.Should().HaveCount(1);
|
||||||
|
nameserver.NameServers[0].Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithNullEditDate_SetsNull()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var nameserver = new Nameserver(1, "Test", "8.8.8.8", "", "", null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
nameserver.EditDate.Should().BeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
77
classlib.tests/Models/SectionTests.cs
Normal file
77
classlib.tests/Models/SectionTests.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class SectionTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var name = "Production";
|
||||||
|
var description = "Production networks section";
|
||||||
|
var masterSectionId = 0;
|
||||||
|
var permissions = "{\"3\":\"2\"}";
|
||||||
|
var strictMode = true;
|
||||||
|
var subnetOrdering = "subnet,asc";
|
||||||
|
var order = 1;
|
||||||
|
var editDate = new DateTime(2026, 1, 5);
|
||||||
|
var showSubnet = true;
|
||||||
|
var showVlan = true;
|
||||||
|
var showVRF = false;
|
||||||
|
var showSupernetOnly = false;
|
||||||
|
var dnsId = 1;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var section = new Section(
|
||||||
|
id, name, description, masterSectionId, permissions, strictMode,
|
||||||
|
subnetOrdering, order, editDate, showSubnet, showVlan, showVRF,
|
||||||
|
showSupernetOnly, dnsId
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
section.Id.Should().Be(id);
|
||||||
|
section.Name.Should().Be(name);
|
||||||
|
section.Description.Should().Be(description);
|
||||||
|
section.MasterSectionId.Should().Be(masterSectionId);
|
||||||
|
section.Permissions.Should().Be(permissions);
|
||||||
|
section.StrictMode.Should().Be(strictMode);
|
||||||
|
section.SubnetOrdering.Should().Be(subnetOrdering);
|
||||||
|
section.Order.Should().Be(order);
|
||||||
|
section.EditDate.Should().Be(editDate);
|
||||||
|
section.ShowSubnet.Should().Be(showSubnet);
|
||||||
|
section.ShowVlan.Should().Be(showVlan);
|
||||||
|
section.ShowVRF.Should().Be(showVRF);
|
||||||
|
section.ShowSupernetOnly.Should().Be(showSupernetOnly);
|
||||||
|
section.DNSId.Should().Be(dnsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Production")]
|
||||||
|
[InlineData("Development")]
|
||||||
|
[InlineData("DMZ")]
|
||||||
|
public void ToString_ReturnsSectionName(string sectionName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var section = new Section(1, sectionName, "", 0, "", false, "", 0, null, false, false, false, false, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = section.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(sectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithNullEditDate_SetsNull()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var section = new Section(1, "Test", "", 0, "", false, "", 0, null, false, false, false, false, 0);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
section.EditDate.Should().BeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
92
classlib.tests/Models/SessionTests.cs
Normal file
92
classlib.tests/Models/SessionTests.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class SessionTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithCredentialsAuth_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var authType = AuthType.credentials;
|
||||||
|
var token = "test-token-123";
|
||||||
|
var appId = "myApp";
|
||||||
|
var url = "https://ipam.example.com";
|
||||||
|
var expires = new DateTime(2026, 12, 31, 23, 59, 59);
|
||||||
|
var credentials = new object(); // Mock credentials
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var session = new Session(authType, token, appId, url, expires, credentials);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
session.AuthType.Should().Be(AuthType.credentials);
|
||||||
|
session.Token.Should().Be(token);
|
||||||
|
session.AppID.Should().Be(appId);
|
||||||
|
session.URL.Should().Be(url);
|
||||||
|
session.Expires.Should().Be(expires);
|
||||||
|
session.Credentials.Should().BeSameAs(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithTokenAuth_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var authType = AuthType.token;
|
||||||
|
var token = "static-api-token";
|
||||||
|
var appId = "apiApp";
|
||||||
|
var url = "https://ipam.test.com";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var session = new Session(authType, token, appId, url, null, null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
session.AuthType.Should().Be(AuthType.token);
|
||||||
|
session.Token.Should().Be(token);
|
||||||
|
session.AppID.Should().Be(appId);
|
||||||
|
session.URL.Should().Be(url);
|
||||||
|
session.Expires.Should().BeNull();
|
||||||
|
session.Credentials.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Token_CanBeModified()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var session = new Session(AuthType.credentials, "old-token", "app", "https://test.com", null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
session.Token = "new-token";
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
session.Token.Should().Be("new-token");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Expires_CanBeModified()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var session = new Session(AuthType.credentials, "token", "app", "https://test.com", null, null);
|
||||||
|
var newExpiry = new DateTime(2027, 1, 1);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
session.Expires = newExpiry;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
session.Expires.Should().Be(newExpiry);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToString_ReturnsDefaultObjectString()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var session = new Session(AuthType.token, "token", "app", "https://test.com", null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = session.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Contain("PS.IPAM.Session");
|
||||||
|
}
|
||||||
|
}
|
||||||
142
classlib.tests/Models/SubnetworkTests.cs
Normal file
142
classlib.tests/Models/SubnetworkTests.cs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class SubnetworkTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var subnet = "192.168.1.0";
|
||||||
|
var mask = 24;
|
||||||
|
var sectionId = 5;
|
||||||
|
var description = "Production network";
|
||||||
|
var linkedSubnet = "linked-123";
|
||||||
|
var firewallObject = "FW_PROD";
|
||||||
|
var vrfId = 2;
|
||||||
|
var masterSubnetId = 0;
|
||||||
|
var allowRequests = true;
|
||||||
|
var vlanId = 100;
|
||||||
|
var showName = true;
|
||||||
|
var deviceId = 10;
|
||||||
|
var permissions = "rw";
|
||||||
|
var pingSubnet = true;
|
||||||
|
var discoverSubnet = false;
|
||||||
|
var resolveDNS = true;
|
||||||
|
var dnsRecursive = false;
|
||||||
|
var dnsRecords = true;
|
||||||
|
var nameserverId = 3;
|
||||||
|
var scanAgent = false;
|
||||||
|
var isFolder = false;
|
||||||
|
var isFull = false;
|
||||||
|
var isPool = true;
|
||||||
|
var tagId = 1;
|
||||||
|
var threshold = 80;
|
||||||
|
var locationId = 4;
|
||||||
|
var editDate = new DateTime(2026, 1, 10);
|
||||||
|
var lastScan = new DateTime(2026, 1, 9);
|
||||||
|
var lastDiscovery = new DateTime(2026, 1, 8);
|
||||||
|
var calculation = new { maxhosts = 254 };
|
||||||
|
var customFields = new Dictionary<string, object> { { "custom_env", "prod" } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var subnetwork = new Subnetwork(
|
||||||
|
id, subnet, mask, sectionId, description, linkedSubnet, firewallObject,
|
||||||
|
vrfId, masterSubnetId, allowRequests, vlanId, showName, deviceId,
|
||||||
|
permissions, pingSubnet, discoverSubnet, resolveDNS, dnsRecursive,
|
||||||
|
dnsRecords, nameserverId, scanAgent, isFolder, isFull, isPool,
|
||||||
|
tagId, threshold, locationId, editDate, lastScan, lastDiscovery,
|
||||||
|
calculation, customFields
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
subnetwork.Id.Should().Be(id);
|
||||||
|
subnetwork.Subnet.Should().Be(subnet);
|
||||||
|
subnetwork.Mask.Should().Be(mask);
|
||||||
|
subnetwork.SectionId.Should().Be(sectionId);
|
||||||
|
subnetwork.Description.Should().Be(description);
|
||||||
|
subnetwork.LinkedSubnet.Should().Be(linkedSubnet);
|
||||||
|
subnetwork.FirewallAddressObject.Should().Be(firewallObject);
|
||||||
|
subnetwork.VrfId.Should().Be(vrfId);
|
||||||
|
subnetwork.MasterSubnetId.Should().Be(masterSubnetId);
|
||||||
|
subnetwork.AllowRequests.Should().Be(allowRequests);
|
||||||
|
subnetwork.VlanId.Should().Be(vlanId);
|
||||||
|
subnetwork.ShowName.Should().Be(showName);
|
||||||
|
subnetwork.DeviceId.Should().Be(deviceId);
|
||||||
|
subnetwork.Permissions.Should().Be(permissions);
|
||||||
|
subnetwork.PingSubnet.Should().Be(pingSubnet);
|
||||||
|
subnetwork.DiscoverSubnet.Should().Be(discoverSubnet);
|
||||||
|
subnetwork.ResolveDNS.Should().Be(resolveDNS);
|
||||||
|
subnetwork.DNSRecursive.Should().Be(dnsRecursive);
|
||||||
|
subnetwork.DNSRecords.Should().Be(dnsRecords);
|
||||||
|
subnetwork.NameserverId.Should().Be(nameserverId);
|
||||||
|
subnetwork.ScanAgent.Should().Be(scanAgent);
|
||||||
|
subnetwork.IsFolder.Should().Be(isFolder);
|
||||||
|
subnetwork.IsFull.Should().Be(isFull);
|
||||||
|
subnetwork.IsPool.Should().Be(isPool);
|
||||||
|
subnetwork.TagId.Should().Be(tagId);
|
||||||
|
subnetwork.Threshold.Should().Be(threshold);
|
||||||
|
subnetwork.LocationId.Should().Be(locationId);
|
||||||
|
subnetwork.EditDate.Should().Be(editDate);
|
||||||
|
subnetwork.LastScan.Should().Be(lastScan);
|
||||||
|
subnetwork.LastDiscovery.Should().Be(lastDiscovery);
|
||||||
|
subnetwork.Calculation.Should().BeEquivalentTo(calculation);
|
||||||
|
subnetwork.ExtendedData.Should().BeEquivalentTo(customFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("192.168.1.0", 24, "192.168.1.0/24")]
|
||||||
|
[InlineData("10.0.0.0", 8, "10.0.0.0/8")]
|
||||||
|
[InlineData("172.16.0.0", 16, "172.16.0.0/16")]
|
||||||
|
[InlineData("192.168.100.0", 30, "192.168.100.0/30")]
|
||||||
|
public void GetCIDR_ReturnsCidrNotation(string subnet, int mask, string expectedCidr)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var subnetwork = CreateSubnetwork(subnet, mask);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = subnetwork.GetCIDR();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(expectedCidr);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToString_ReturnsCidrNotation()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var subnetwork = CreateSubnetwork("10.10.0.0", 16);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = subnetwork.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("10.10.0.0/16");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToString_EqualsGetCIDR()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var subnetwork = CreateSubnetwork("172.20.0.0", 12);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
subnetwork.ToString().Should().Be(subnetwork.GetCIDR());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Subnetwork CreateSubnetwork(string subnet, int mask)
|
||||||
|
{
|
||||||
|
return new Subnetwork(
|
||||||
|
1, subnet, mask, 1, "", "", "",
|
||||||
|
0, 0, false, 0, false, 0,
|
||||||
|
"", false, false, false, false,
|
||||||
|
false, 0, false, false, false, false,
|
||||||
|
0, 0, 0, null, null, null,
|
||||||
|
new object(), null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
classlib.tests/Models/TagTests.cs
Normal file
77
classlib.tests/Models/TagTests.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class TagTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var type = "Used";
|
||||||
|
var showTag = true;
|
||||||
|
var bgColor = "#5cb85c";
|
||||||
|
var fgColor = "#ffffff";
|
||||||
|
var compress = "Yes";
|
||||||
|
var locked = "No";
|
||||||
|
var updateTag = true;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var tag = new Tag(id, type, showTag, bgColor, fgColor, compress, locked, updateTag);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
tag.Id.Should().Be(id);
|
||||||
|
tag.Type.Should().Be(type);
|
||||||
|
tag.ShowTag.Should().Be(showTag);
|
||||||
|
tag.BGColor.Should().Be(bgColor);
|
||||||
|
tag.FGColor.Should().Be(fgColor);
|
||||||
|
tag.Compress.Should().BeTrue();
|
||||||
|
tag.Locked.Should().BeFalse();
|
||||||
|
tag.UpdateTag.Should().Be(updateTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Yes", true)]
|
||||||
|
[InlineData("No", false)]
|
||||||
|
[InlineData("", false)]
|
||||||
|
[InlineData("yes", false)] // Case sensitive
|
||||||
|
[InlineData("true", false)] // Only "Yes" is true
|
||||||
|
public void StringToBool_ConvertsCorrectly(string input, bool expected)
|
||||||
|
{
|
||||||
|
// The StringToBool is private, so we test through the constructor
|
||||||
|
// Using Compress field which uses StringToBool
|
||||||
|
var tag = new Tag(1, "Test", false, "", "", input, "No", false);
|
||||||
|
|
||||||
|
tag.Compress.Should().Be(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Used")]
|
||||||
|
[InlineData("Available")]
|
||||||
|
[InlineData("Reserved")]
|
||||||
|
[InlineData("DHCP")]
|
||||||
|
public void ToString_ReturnsTagType(string tagType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var tag = new Tag(1, tagType, false, "", "", "No", "No", false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = tag.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(tagType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Locked_WithYes_IsTrue()
|
||||||
|
{
|
||||||
|
// Arrange & Act
|
||||||
|
var tag = new Tag(1, "Test", false, "", "", "No", "Yes", false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
tag.Locked.Should().BeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
76
classlib.tests/Models/VlanTests.cs
Normal file
76
classlib.tests/Models/VlanTests.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class VlanTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var vlanId = 100;
|
||||||
|
var domainId = 1;
|
||||||
|
var name = "Production VLAN";
|
||||||
|
var number = 100;
|
||||||
|
var description = "Production network VLAN";
|
||||||
|
var editDate = new DateTime(2026, 1, 15);
|
||||||
|
var customerId = 50;
|
||||||
|
var customFields = new Dictionary<string, object> { { "custom_location", "DC1" } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var vlan = new Vlan(vlanId, domainId, name, number, description, editDate, customerId, customFields);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
vlan.Id.Should().Be(vlanId);
|
||||||
|
vlan.VlanId.Should().Be(vlanId);
|
||||||
|
vlan.DomainId.Should().Be(domainId);
|
||||||
|
vlan.Name.Should().Be(name);
|
||||||
|
vlan.Number.Should().Be(number);
|
||||||
|
vlan.Description.Should().Be(description);
|
||||||
|
vlan.EditDate.Should().Be(editDate);
|
||||||
|
vlan.CustomerId.Should().Be(customerId);
|
||||||
|
vlan.ExtendedData.Should().BeEquivalentTo(customFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Id_And_VlanId_AreSameValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var vlanId = 200;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var vlan = new Vlan(vlanId, 1, "Test", 200, "", null, 0, null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
vlan.Id.Should().Be(vlan.VlanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(100)]
|
||||||
|
[InlineData(4094)]
|
||||||
|
public void ToString_ReturnsVlanNumber(int vlanNumber)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var vlan = new Vlan(1, 1, "Test", vlanNumber, "", null, 0, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = vlan.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(vlanNumber.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithNullOptionalFields_SetsNullValues()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var vlan = new Vlan(1, 1, "Test", 10, "", null, 0, null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
vlan.EditDate.Should().BeNull();
|
||||||
|
vlan.ExtendedData.Should().BeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
60
classlib.tests/Models/VrfTests.cs
Normal file
60
classlib.tests/Models/VrfTests.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
namespace PS.IPAM.Tests.Models;
|
||||||
|
|
||||||
|
using FluentAssertions;
|
||||||
|
using PS.IPAM;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class VrfTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_SetsAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = 1;
|
||||||
|
var name = "VRF_PROD";
|
||||||
|
var rd = "65000:100";
|
||||||
|
var description = "Production VRF";
|
||||||
|
var sections = "1;2;3";
|
||||||
|
var editDate = new DateTime(2026, 1, 10);
|
||||||
|
var customFields = new Dictionary<string, object> { { "custom_tenant", "CustomerA" } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var vrf = new Vrf(id, name, rd, description, sections, editDate, customFields);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
vrf.Id.Should().Be(id);
|
||||||
|
vrf.Name.Should().Be(name);
|
||||||
|
vrf.RouteDistinguisher.Should().Be(rd);
|
||||||
|
vrf.Description.Should().Be(description);
|
||||||
|
vrf.Sections.Should().Be(sections);
|
||||||
|
vrf.EditDate.Should().Be(editDate);
|
||||||
|
vrf.ExtendedData.Should().BeEquivalentTo(customFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("VRF_DEFAULT")]
|
||||||
|
[InlineData("Production_VRF")]
|
||||||
|
[InlineData("CUSTOMER_A")]
|
||||||
|
public void ToString_ReturnsVrfName(string vrfName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var vrf = new Vrf(1, vrfName, "65000:1", "", "", null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = vrf.ToString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(vrfName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_WithNullOptionalFields_SetsNullValues()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var vrf = new Vrf(1, "Test", "65000:1", "", "", null, null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
vrf.EditDate.Should().BeNull();
|
||||||
|
vrf.ExtendedData.Should().BeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
classlib.tests/TestCollections.cs
Normal file
32
classlib.tests/TestCollections.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
namespace PS.IPAM.Tests;
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection definition for tests that share static state (SessionManager, RequestHelper.TestHttpHandler).
|
||||||
|
/// Tests in this collection will run sequentially, not in parallel.
|
||||||
|
/// </summary>
|
||||||
|
[CollectionDefinition("Sequential")]
|
||||||
|
public class SequentialCollection : ICollectionFixture<SequentialTestFixture>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fixture for sequential test collection.
|
||||||
|
/// </summary>
|
||||||
|
public class SequentialTestFixture : IDisposable
|
||||||
|
{
|
||||||
|
public SequentialTestFixture()
|
||||||
|
{
|
||||||
|
// Clean up before tests
|
||||||
|
PS.IPAM.Helpers.SessionManager.CloseSession();
|
||||||
|
PS.IPAM.Helpers.RequestHelper.TestHttpHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Clean up after tests
|
||||||
|
PS.IPAM.Helpers.SessionManager.CloseSession();
|
||||||
|
PS.IPAM.Helpers.RequestHelper.TestHttpHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
classlib.tests/classlib.tests.csproj
Normal file
33
classlib.tests/classlib.tests.csproj
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
<RootNamespace>PS.IPAM.Tests</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.6.4" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
|
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\classlib\classlib.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
43
classlib/Cmdlets/AssignTagCmdlet.cs
Normal file
43
classlib/Cmdlets/AssignTagCmdlet.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet("Assign", "Tag")]
|
||||||
|
public class AssignTagCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Address? AddressObject { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
Position = 1)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Tag? Tag { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string> { AddressObject!.Id.ToString() };
|
||||||
|
var body = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "tag", Tag!.Id }
|
||||||
|
};
|
||||||
|
|
||||||
|
RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, body, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "AssignTagError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
classlib/Cmdlets/CloseSessionCmdlet.cs
Normal file
21
classlib/Cmdlets/CloseSessionCmdlet.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Close, "Session")]
|
||||||
|
public class CloseSessionCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RequestHelper.InvokeRequest("DELETE", controllers.user, null, null, null, null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
SessionManager.CloseSession();
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "CloseSessionError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
162
classlib/Cmdlets/GetAddressCmdlet.cs
Normal file
162
classlib/Cmdlets/GetAddressCmdlet.cs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Address", DefaultParameterSetName = "ByID")]
|
||||||
|
[OutputType(typeof(Address))]
|
||||||
|
public class GetAddressCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByIP")]
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1,
|
||||||
|
ParameterSetName = "BySubnetId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public IPAddress? IP { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByHostName")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? HostName { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByHostBase")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? HostBase { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByTag")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? SubnetId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetCIDR")]
|
||||||
|
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? SubnetCIDR { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var controller = controllers.addresses;
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
|
||||||
|
switch (ParameterSetName)
|
||||||
|
{
|
||||||
|
case "ByID":
|
||||||
|
identifiers.Add(Id.ToString());
|
||||||
|
break;
|
||||||
|
case "ByIP":
|
||||||
|
identifiers.Add("search");
|
||||||
|
identifiers.Add(IP!.ToString());
|
||||||
|
break;
|
||||||
|
case "ByHostName":
|
||||||
|
identifiers.Add("search_hostname");
|
||||||
|
identifiers.Add(HostName!);
|
||||||
|
break;
|
||||||
|
case "ByHostBase":
|
||||||
|
identifiers.Add("search_hostbase");
|
||||||
|
identifiers.Add(HostBase!);
|
||||||
|
break;
|
||||||
|
case "ByTag":
|
||||||
|
identifiers.Add("tags");
|
||||||
|
identifiers.Add(TagId!.Value.ToString());
|
||||||
|
identifiers.Add("addresses");
|
||||||
|
break;
|
||||||
|
case "BySubnetId":
|
||||||
|
if (IP != null)
|
||||||
|
{
|
||||||
|
identifiers.Add(IP.ToString());
|
||||||
|
identifiers.Add(SubnetId!.Value.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
controller = controllers.subnets;
|
||||||
|
identifiers.Add(SubnetId!.Value.ToString());
|
||||||
|
identifiers.Add("addresses");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "BySubnetCIDR":
|
||||||
|
controller = controllers.subnets;
|
||||||
|
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", SubnetCIDR! })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (subnet == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find subnet!");
|
||||||
|
}
|
||||||
|
var subnetObj = subnet as Subnetwork;
|
||||||
|
identifiers.Add(subnetObj!.Id.ToString());
|
||||||
|
identifiers.Add("addresses");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controller, types.Address, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetAddressError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
classlib/Cmdlets/GetFirstFreeIPCmdlet.cs
Normal file
79
classlib/Cmdlets/GetFirstFreeIPCmdlet.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "FirstFreeIP", DefaultParameterSetName = "ByID")]
|
||||||
|
public class GetFirstFreeIPCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByCIDR")]
|
||||||
|
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? CIDR { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Subnetwork? SubnetObject { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int subnetId;
|
||||||
|
if (ParameterSetName == "ByCIDR")
|
||||||
|
{
|
||||||
|
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR! })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (subnet == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find subnet!");
|
||||||
|
}
|
||||||
|
var subnetObj = subnet as Subnetwork;
|
||||||
|
subnetId = subnetObj!.Id;
|
||||||
|
}
|
||||||
|
else if (ParameterSetName == "BySubnetObject")
|
||||||
|
{
|
||||||
|
subnetId = SubnetObject!.Id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subnetId = Id!.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var identifiers = new List<string> { subnetId.ToString(), "first_free" };
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.subnets, null, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
WriteObject(new { Ip = result.ToString() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetFirstFreeIPError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
classlib/Cmdlets/GetL2DomainCmdlet.cs
Normal file
54
classlib/Cmdlets/GetL2DomainCmdlet.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "L2Domain", DefaultParameterSetName = "ByID")]
|
||||||
|
[OutputType(typeof(Domain))]
|
||||||
|
public class GetL2DomainCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
if (Id.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(Id.Value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.l2domains, types.Domain, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetL2DomainError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
classlib/Cmdlets/GetNameserverCmdlet.cs
Normal file
54
classlib/Cmdlets/GetNameserverCmdlet.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Nameserver", DefaultParameterSetName = "NoParams")]
|
||||||
|
[OutputType(typeof(Nameserver))]
|
||||||
|
public class GetNameserverCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
if (Id.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(Id.Value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.tools, types.Nameserver, subcontrollers.nameservers, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetNameserverError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
148
classlib/Cmdlets/GetPermissionsCmdlet.cs
Normal file
148
classlib/Cmdlets/GetPermissionsCmdlet.cs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Permissions")]
|
||||||
|
public class GetPermissionsCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByIP")]
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1,
|
||||||
|
ParameterSetName = "BySubnetId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public IPAddress? IP { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByHostName")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? HostName { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByTag")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? SubnetId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetCIDR")]
|
||||||
|
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? SubnetCIDR { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var controller = controllers.addresses;
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
|
||||||
|
switch (ParameterSetName)
|
||||||
|
{
|
||||||
|
case "ByID":
|
||||||
|
identifiers.Add(Id!);
|
||||||
|
break;
|
||||||
|
case "ByIP":
|
||||||
|
identifiers.Add("search");
|
||||||
|
identifiers.Add(IP!.ToString());
|
||||||
|
break;
|
||||||
|
case "ByHostName":
|
||||||
|
identifiers.Add("search_hostname");
|
||||||
|
identifiers.Add(HostName!);
|
||||||
|
break;
|
||||||
|
case "ByTag":
|
||||||
|
identifiers.Add("tags");
|
||||||
|
identifiers.Add(TagId!);
|
||||||
|
identifiers.Add("addresses");
|
||||||
|
break;
|
||||||
|
case "BySubnetId":
|
||||||
|
if (IP != null)
|
||||||
|
{
|
||||||
|
identifiers.Add(IP.ToString());
|
||||||
|
identifiers.Add(SubnetId!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
controller = controllers.subnets;
|
||||||
|
identifiers.Add(SubnetId!);
|
||||||
|
identifiers.Add("addresses");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "BySubnetCIDR":
|
||||||
|
controller = controllers.subnets;
|
||||||
|
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", SubnetCIDR! })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (subnet == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find subnet!");
|
||||||
|
}
|
||||||
|
var subnetObj = subnet as Subnetwork;
|
||||||
|
identifiers.Add(subnetObj!.Id.ToString());
|
||||||
|
identifiers.Add("addresses");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controller, null, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetPermissionsError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
classlib/Cmdlets/GetSectionCmdlet.cs
Normal file
65
classlib/Cmdlets/GetSectionCmdlet.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Section", DefaultParameterSetName = "NoParams")]
|
||||||
|
[OutputType(typeof(Section))]
|
||||||
|
public class GetSectionCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByName")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
if (ParameterSetName == "ByID" && Id.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(Id.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (ParameterSetName == "ByName")
|
||||||
|
{
|
||||||
|
identifiers.Add(Name!);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetSectionError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
261
classlib/Cmdlets/GetSubnetCmdlet.cs
Normal file
261
classlib/Cmdlets/GetSubnetCmdlet.cs
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Subnet", DefaultParameterSetName = "NoParams")]
|
||||||
|
[OutputType(typeof(Subnetwork))]
|
||||||
|
public class GetSubnetCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByCIDR")]
|
||||||
|
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? CIDR { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySectionId")]
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2,
|
||||||
|
ParameterSetName = "ByVlanNumber")]
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1,
|
||||||
|
ParameterSetName = "ByVlanId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? SectionId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySectionName")]
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 3,
|
||||||
|
ParameterSetName = "ByVlanNumber")]
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2,
|
||||||
|
ParameterSetName = "ByVlanId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? SectionName { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByVrfId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? VrfId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByVlanId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? VlanId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByVlanNumber")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? VlanNumber { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
public SwitchParameter Slaves { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
public SwitchParameter Recurse { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1,
|
||||||
|
ParameterSetName = "ByVlanNumber")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? VlanDomainId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var controller = controllers.subnets;
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
|
||||||
|
switch (ParameterSetName)
|
||||||
|
{
|
||||||
|
case "ByCIDR":
|
||||||
|
identifiers.Add("cidr");
|
||||||
|
identifiers.Add(CIDR!);
|
||||||
|
break;
|
||||||
|
case "ByID":
|
||||||
|
identifiers.Add(Id!.Value.ToString());
|
||||||
|
if (Slaves.IsPresent)
|
||||||
|
{
|
||||||
|
identifiers.Add(Recurse.IsPresent ? "slaves_recursive" : "slaves");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "BySectionId":
|
||||||
|
controller = controllers.sections;
|
||||||
|
identifiers.Add(SectionId!.Value.ToString());
|
||||||
|
identifiers.Add("subnets");
|
||||||
|
break;
|
||||||
|
case "BySectionName":
|
||||||
|
controller = controllers.sections;
|
||||||
|
var section = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName! })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (section == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find section!");
|
||||||
|
}
|
||||||
|
var sectionObj = section as Section;
|
||||||
|
identifiers.Add(sectionObj!.Id.ToString());
|
||||||
|
identifiers.Add("subnets");
|
||||||
|
break;
|
||||||
|
case "ByVrfId":
|
||||||
|
controller = controllers.vrf;
|
||||||
|
identifiers.Add(VrfId!.Value.ToString());
|
||||||
|
identifiers.Add("subnets");
|
||||||
|
break;
|
||||||
|
case "ByVlanId":
|
||||||
|
controller = controllers.vlan;
|
||||||
|
identifiers.Add(VlanId!.Value.ToString());
|
||||||
|
identifiers.Add("subnets");
|
||||||
|
if (SectionId.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(SectionId.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(SectionName))
|
||||||
|
{
|
||||||
|
var section2 = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (section2 != null)
|
||||||
|
{
|
||||||
|
var sectionObj2 = section2 as Section;
|
||||||
|
identifiers.Add(sectionObj2!.Id.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ByVlanNumber":
|
||||||
|
controller = controllers.vlan;
|
||||||
|
var vlans = RequestHelper.InvokeRequest("GET", controllers.vlan, types.Vlan, null, null, new[] { "search", VlanNumber!.Value.ToString() })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (vlans == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find Vlan!");
|
||||||
|
}
|
||||||
|
var vlanList = vlans as System.Collections.IEnumerable;
|
||||||
|
Vlan? foundVlan = null;
|
||||||
|
if (vlanList != null)
|
||||||
|
{
|
||||||
|
foreach (var v in vlanList)
|
||||||
|
{
|
||||||
|
if (v is Vlan vlan)
|
||||||
|
{
|
||||||
|
if (VlanDomainId.HasValue && vlan.DomainId != VlanDomainId.Value)
|
||||||
|
continue;
|
||||||
|
if (foundVlan != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"More than one vLan with {VlanNumber} number is present!");
|
||||||
|
}
|
||||||
|
foundVlan = vlan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundVlan == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find Vlan!");
|
||||||
|
}
|
||||||
|
identifiers.Add(foundVlan.Id.ToString());
|
||||||
|
identifiers.Add("subnets");
|
||||||
|
if (SectionId.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(SectionId.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(SectionName))
|
||||||
|
{
|
||||||
|
var section3 = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (section3 != null)
|
||||||
|
{
|
||||||
|
var sectionObj3 = section3 as Section;
|
||||||
|
identifiers.Add(sectionObj3!.Id.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controller, types.Subnetwork, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetSubnetError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
classlib/Cmdlets/GetSubnetUsageCmdlet.cs
Normal file
66
classlib/Cmdlets/GetSubnetUsageCmdlet.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "SubnetUsage", DefaultParameterSetName = "ByID")]
|
||||||
|
public class GetSubnetUsageCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByCIDR")]
|
||||||
|
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? CIDR { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int subnetId;
|
||||||
|
if (ParameterSetName == "ByCIDR")
|
||||||
|
{
|
||||||
|
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR! })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (subnet == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot find subnet!");
|
||||||
|
}
|
||||||
|
var subnetObj = subnet as Subnetwork;
|
||||||
|
subnetId = subnetObj!.Id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subnetId = Id!.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var identifiers = new List<string> { subnetId.ToString(), "usage" };
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.subnets, null, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetSubnetUsageError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
98
classlib/Cmdlets/GetTagCmdlet.cs
Normal file
98
classlib/Cmdlets/GetTagCmdlet.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Tag", DefaultParameterSetName = "NoParams")]
|
||||||
|
[OutputType(typeof(Tag))]
|
||||||
|
public class GetTagCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByAddressObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Address? AddressObject { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Subnetwork? SubnetObject { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string> { "tags" };
|
||||||
|
|
||||||
|
switch (ParameterSetName)
|
||||||
|
{
|
||||||
|
case "ByID":
|
||||||
|
if (Id.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(Id.Value.ToString());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ByAddressObject":
|
||||||
|
if (AddressObject?.TagId > 0)
|
||||||
|
{
|
||||||
|
identifiers.Add(AddressObject.TagId.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "BySubnetObject":
|
||||||
|
if (SubnetObject?.TagId > 0)
|
||||||
|
{
|
||||||
|
identifiers.Add(SubnetObject.TagId.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Tag, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetTagError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
134
classlib/Cmdlets/GetVlanCmdlet.cs
Normal file
134
classlib/Cmdlets/GetVlanCmdlet.cs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Vlan", DefaultParameterSetName = "NoParams")]
|
||||||
|
[OutputType(typeof(Vlan))]
|
||||||
|
public class GetVlanCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByNumber")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Number { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByL2Domain")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? L2DomainId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Subnetwork? SubnetObject { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByDomainObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Domain? DomainObject { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var controller = controllers.vlan;
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
|
||||||
|
switch (ParameterSetName)
|
||||||
|
{
|
||||||
|
case "ByID":
|
||||||
|
identifiers.Add(Id!.Value.ToString());
|
||||||
|
break;
|
||||||
|
case "ByNumber":
|
||||||
|
identifiers.Add("search");
|
||||||
|
identifiers.Add(Number!.Value.ToString());
|
||||||
|
break;
|
||||||
|
case "ByL2Domain":
|
||||||
|
controller = controllers.l2domains;
|
||||||
|
identifiers.Add(L2DomainId!.Value.ToString());
|
||||||
|
identifiers.Add(subcontrollers.vlans.ToString());
|
||||||
|
break;
|
||||||
|
case "BySubnetObject":
|
||||||
|
if (SubnetObject != null && SubnetObject.VlanId > 0)
|
||||||
|
{
|
||||||
|
identifiers.Add(SubnetObject.VlanId.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ByDomainObject":
|
||||||
|
if (DomainObject != null)
|
||||||
|
{
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.l2domains, types.Vlan, subcontrollers.vlans, null, new[] { DomainObject.Id.ToString() })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlanResult = RequestHelper.InvokeRequest("GET", controller, types.Vlan, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (vlanResult != null)
|
||||||
|
{
|
||||||
|
if (vlanResult is System.Collections.IEnumerable enumerable && !(vlanResult is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(vlanResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetVlanError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
classlib/Cmdlets/GetVrfCmdlet.cs
Normal file
54
classlib/Cmdlets/GetVrfCmdlet.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Get, "Vrf", DefaultParameterSetName = "NoParams")]
|
||||||
|
[OutputType(typeof(Vrf))]
|
||||||
|
public class GetVrfCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string>();
|
||||||
|
if (Id.HasValue)
|
||||||
|
{
|
||||||
|
identifiers.Add(Id.Value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("GET", controllers.vrf, types.Vrf, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result is System.Collections.IEnumerable enumerable && !(result is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
WriteObject(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteObject(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "GetVrfError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
219
classlib/Cmdlets/NewAddressCmdlet.cs
Normal file
219
classlib/Cmdlets/NewAddressCmdlet.cs
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.New, "Address", DefaultParameterSetName = "BySubnetId")]
|
||||||
|
[OutputType(typeof(Address))]
|
||||||
|
public class NewAddressCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetId")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? SubnetId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "BySubnetObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Subnetwork? SubnetObject { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string IP { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2)]
|
||||||
|
public SwitchParameter Gateway { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 3)]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 4)]
|
||||||
|
public string? Hostname { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 5)]
|
||||||
|
public string? MAC { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 6)]
|
||||||
|
public string? Owner { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 7)]
|
||||||
|
public int? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 8)]
|
||||||
|
public SwitchParameter PTRIgnore { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 7)]
|
||||||
|
public int? PTRId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 10)]
|
||||||
|
public string? Note { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 11)]
|
||||||
|
public SwitchParameter ExcludePing { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 12)]
|
||||||
|
public int? DeviceId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 13)]
|
||||||
|
public string? Port { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 14)]
|
||||||
|
public object? CustomFields { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int actualSubnetId;
|
||||||
|
if (ParameterSetName == "BySubnetObject")
|
||||||
|
{
|
||||||
|
actualSubnetId = SubnetObject!.Id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actualSubnetId = SubnetId!.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var body = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "subnetId", actualSubnetId },
|
||||||
|
{ "ip", IP }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Gateway.IsPresent)
|
||||||
|
body["is_gateway"] = "1";
|
||||||
|
if (!string.IsNullOrEmpty(Description))
|
||||||
|
body["description"] = Description;
|
||||||
|
if (!string.IsNullOrEmpty(Hostname))
|
||||||
|
body["hostname"] = Hostname;
|
||||||
|
if (!string.IsNullOrEmpty(MAC))
|
||||||
|
body["mac"] = MAC;
|
||||||
|
if (!string.IsNullOrEmpty(Owner))
|
||||||
|
body["owner"] = Owner;
|
||||||
|
if (TagId.HasValue)
|
||||||
|
body["tag"] = TagId.Value;
|
||||||
|
if (PTRIgnore.IsPresent)
|
||||||
|
body["PTRignore"] = "1";
|
||||||
|
if (PTRId.HasValue)
|
||||||
|
body["PTR"] = PTRId.Value;
|
||||||
|
if (!string.IsNullOrEmpty(Note))
|
||||||
|
body["note"] = Note;
|
||||||
|
if (ExcludePing.IsPresent)
|
||||||
|
body["excludePing"] = "1";
|
||||||
|
if (DeviceId.HasValue)
|
||||||
|
body["deviceId"] = DeviceId.Value;
|
||||||
|
if (!string.IsNullOrEmpty(Port))
|
||||||
|
body["port"] = Port;
|
||||||
|
|
||||||
|
if (CustomFields != null)
|
||||||
|
{
|
||||||
|
var customDict = ConvertCustomFields(CustomFields);
|
||||||
|
foreach (var kvp in customDict)
|
||||||
|
{
|
||||||
|
body[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, body, null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "search", IP })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (address != null)
|
||||||
|
{
|
||||||
|
WriteObject(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "NewAddressError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> ConvertCustomFields(object customFields)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object>();
|
||||||
|
if (customFields is PSObject psobj)
|
||||||
|
{
|
||||||
|
foreach (var prop in psobj.Properties)
|
||||||
|
{
|
||||||
|
dict[prop.Name] = prop.Value ?? new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (customFields is Dictionary<string, object> dictObj)
|
||||||
|
{
|
||||||
|
return dictObj;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
||||||
190
classlib/Cmdlets/NewFirstFreeIPCmdlet.cs
Normal file
190
classlib/Cmdlets/NewFirstFreeIPCmdlet.cs
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.New, "FirstFreeIP")]
|
||||||
|
[OutputType(typeof(Address))]
|
||||||
|
public class NewFirstFreeIPCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string SubnetId { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2)]
|
||||||
|
public SwitchParameter Gateway { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 3)]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 4)]
|
||||||
|
public string? Hostname { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 5)]
|
||||||
|
public string? MAC { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 6)]
|
||||||
|
public string? Owner { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 7)]
|
||||||
|
public string? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 8)]
|
||||||
|
public SwitchParameter PTRIgnore { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 9)]
|
||||||
|
public string? PTRId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 10)]
|
||||||
|
public string? Note { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 11)]
|
||||||
|
public SwitchParameter ExcludePing { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 12)]
|
||||||
|
public string? DeviceId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 13)]
|
||||||
|
public string? Port { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true)]
|
||||||
|
public object? CustomFields { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string> { "first_free" };
|
||||||
|
var body = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "subnetId", SubnetId }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Gateway.IsPresent)
|
||||||
|
body["is_gateway"] = "1";
|
||||||
|
if (!string.IsNullOrEmpty(Description))
|
||||||
|
body["description"] = Description;
|
||||||
|
if (!string.IsNullOrEmpty(Hostname))
|
||||||
|
body["hostname"] = Hostname;
|
||||||
|
if (!string.IsNullOrEmpty(MAC))
|
||||||
|
body["mac"] = MAC;
|
||||||
|
if (!string.IsNullOrEmpty(Owner))
|
||||||
|
body["owner"] = Owner;
|
||||||
|
if (!string.IsNullOrEmpty(TagId))
|
||||||
|
body["tag"] = TagId;
|
||||||
|
if (PTRIgnore.IsPresent)
|
||||||
|
body["PTRignore"] = "1";
|
||||||
|
if (!string.IsNullOrEmpty(PTRId))
|
||||||
|
body["PTR"] = PTRId;
|
||||||
|
if (!string.IsNullOrEmpty(Note))
|
||||||
|
body["note"] = Note;
|
||||||
|
if (ExcludePing.IsPresent)
|
||||||
|
body["excludePing"] = "1";
|
||||||
|
if (!string.IsNullOrEmpty(DeviceId))
|
||||||
|
body["deviceId"] = DeviceId;
|
||||||
|
if (!string.IsNullOrEmpty(Port))
|
||||||
|
body["port"] = Port;
|
||||||
|
|
||||||
|
if (CustomFields != null)
|
||||||
|
{
|
||||||
|
var customDict = ConvertCustomFields(CustomFields);
|
||||||
|
foreach (var kvp in customDict)
|
||||||
|
{
|
||||||
|
body[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, body, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
var ip = result.ToString();
|
||||||
|
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "search", ip })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (address != null)
|
||||||
|
{
|
||||||
|
WriteObject(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "NewFirstFreeIPError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> ConvertCustomFields(object customFields)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object>();
|
||||||
|
if (customFields is PSObject psobj)
|
||||||
|
{
|
||||||
|
foreach (var prop in psobj.Properties)
|
||||||
|
{
|
||||||
|
dict[prop.Name] = prop.Value ?? new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (customFields is Dictionary<string, object> dictObj)
|
||||||
|
{
|
||||||
|
return dictObj;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
||||||
81
classlib/Cmdlets/NewSessionCmdlet.cs
Normal file
81
classlib/Cmdlets/NewSessionCmdlet.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.New, "Session", DefaultParameterSetName = "Credentials")]
|
||||||
|
public class NewSessionCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
[ValidatePattern("^https?://")]
|
||||||
|
public string URL { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string AppID { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2,
|
||||||
|
ParameterSetName = "Credentials")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public PSCredential? Credentials { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2,
|
||||||
|
ParameterSetName = "Token")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string? Token { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 3)]
|
||||||
|
public SwitchParameter IgnoreSSL { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Session session;
|
||||||
|
if (ParameterSetName == "Credentials" && Credentials != null)
|
||||||
|
{
|
||||||
|
session = SessionManager.CreateSessionWithCredentials(
|
||||||
|
URL,
|
||||||
|
AppID,
|
||||||
|
Credentials,
|
||||||
|
IgnoreSSL.IsPresent
|
||||||
|
).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
else if (ParameterSetName == "Token" && Token != null)
|
||||||
|
{
|
||||||
|
session = SessionManager.CreateSessionWithToken(URL, AppID, Token);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid parameter set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "NewSessionError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
231
classlib/Cmdlets/NewSubnetCmdlet.cs
Normal file
231
classlib/Cmdlets/NewSubnetCmdlet.cs
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.New, "Subnet")]
|
||||||
|
[OutputType(typeof(Subnetwork))]
|
||||||
|
public class NewSubnetCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0)]
|
||||||
|
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public string CIDR { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 1)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int SectionId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 2)]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 3)]
|
||||||
|
public int? VlanId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 4)]
|
||||||
|
public int? VrfId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 5)]
|
||||||
|
public int? MasterSubnetId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 6)]
|
||||||
|
public int? NameserverId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 7)]
|
||||||
|
public SwitchParameter ShowName { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 8)]
|
||||||
|
public SwitchParameter DNSRecursive { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 9)]
|
||||||
|
public SwitchParameter DNSRecords { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 10)]
|
||||||
|
public SwitchParameter AllowRequests { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 11)]
|
||||||
|
public int? ScanAgentId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 12)]
|
||||||
|
public SwitchParameter DiscoverSubnet { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 12)]
|
||||||
|
public SwitchParameter IsFull { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 12)]
|
||||||
|
public int? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 13)]
|
||||||
|
[ValidateRange(1, 100)]
|
||||||
|
public int? Threshold { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 14)]
|
||||||
|
public int? LocationId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 15)]
|
||||||
|
public object? CustomFields { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parts = CIDR.Split('/');
|
||||||
|
var body = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "subnet", parts[0] },
|
||||||
|
{ "mask", parts[1] },
|
||||||
|
{ "sectionId", SectionId }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Description))
|
||||||
|
body["description"] = Description;
|
||||||
|
if (VlanId.HasValue)
|
||||||
|
body["vlanId"] = VlanId.Value;
|
||||||
|
if (VrfId.HasValue)
|
||||||
|
body["vrfId"] = VrfId.Value;
|
||||||
|
if (MasterSubnetId.HasValue)
|
||||||
|
body["masterSubnetId"] = MasterSubnetId.Value;
|
||||||
|
if (NameserverId.HasValue)
|
||||||
|
body["nameserverId"] = NameserverId.Value;
|
||||||
|
if (ShowName.IsPresent)
|
||||||
|
body["showName"] = "1";
|
||||||
|
if (DNSRecursive.IsPresent)
|
||||||
|
body["DNSrecursive"] = "1";
|
||||||
|
if (DNSRecords.IsPresent)
|
||||||
|
body["DNSrecords"] = "1";
|
||||||
|
if (AllowRequests.IsPresent)
|
||||||
|
body["allowRequests"] = "1";
|
||||||
|
if (ScanAgentId.HasValue)
|
||||||
|
body["scanAgent"] = ScanAgentId.Value;
|
||||||
|
if (DiscoverSubnet.IsPresent)
|
||||||
|
body["discoverSubnet"] = "1";
|
||||||
|
if (IsFull.IsPresent)
|
||||||
|
body["isFull"] = "1";
|
||||||
|
if (TagId.HasValue)
|
||||||
|
body["state"] = TagId.Value;
|
||||||
|
if (Threshold.HasValue)
|
||||||
|
body["threshold"] = Threshold.Value;
|
||||||
|
if (LocationId.HasValue)
|
||||||
|
body["location"] = LocationId.Value;
|
||||||
|
|
||||||
|
if (CustomFields != null)
|
||||||
|
{
|
||||||
|
var customDict = ConvertCustomFields(CustomFields);
|
||||||
|
foreach (var kvp in customDict)
|
||||||
|
{
|
||||||
|
body[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = RequestHelper.InvokeRequest("POST", controllers.subnets, null, null, body, null)
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
// Get the created subnet
|
||||||
|
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR })
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (subnet != null)
|
||||||
|
{
|
||||||
|
WriteObject(subnet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "NewSubnetError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> ConvertCustomFields(object customFields)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object>();
|
||||||
|
if (customFields is PSObject psobj)
|
||||||
|
{
|
||||||
|
foreach (var prop in psobj.Properties)
|
||||||
|
{
|
||||||
|
dict[prop.Name] = prop.Value ?? new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (customFields is Dictionary<string, object> dictObj)
|
||||||
|
{
|
||||||
|
return dictObj;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
classlib/Cmdlets/RemoveAddressCmdlet.cs
Normal file
51
classlib/Cmdlets/RemoveAddressCmdlet.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Remove, "Address", DefaultParameterSetName = "ByID")]
|
||||||
|
public class RemoveAddressCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByID")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByAddressObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Address? AddressObject { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int addressId;
|
||||||
|
if (ParameterSetName == "ByID")
|
||||||
|
{
|
||||||
|
addressId = Id!.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addressId = AddressObject!.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var identifiers = new List<string> { addressId.ToString() };
|
||||||
|
RequestHelper.InvokeRequest("DELETE", controllers.addresses, null, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "RemoveAddressError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
186
classlib/Cmdlets/SetAddressCmdlet.cs
Normal file
186
classlib/Cmdlets/SetAddressCmdlet.cs
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Set, "Address", DefaultParameterSetName = "ById")]
|
||||||
|
[OutputType(typeof(Address))]
|
||||||
|
public class SetAddressCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ById")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0,
|
||||||
|
ParameterSetName = "ByAddressObject")]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public Address? AddressObject { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Position = 1,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
ParameterSetName = "ById")]
|
||||||
|
public bool? Gateway { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Position = 2,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
ParameterSetName = "ById")]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 3)]
|
||||||
|
public string? Hostname { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 4)]
|
||||||
|
public string? MAC { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 5)]
|
||||||
|
public string? Owner { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 6)]
|
||||||
|
public int? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 7)]
|
||||||
|
public bool? PTRIgnore { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 8)]
|
||||||
|
public int? PTRId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 9)]
|
||||||
|
public string? Note { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 10)]
|
||||||
|
public bool? ExcludePing { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 11)]
|
||||||
|
public int? DeviceId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false,
|
||||||
|
Position = 12)]
|
||||||
|
public string? Port { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public object? CustomFields { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int addressId;
|
||||||
|
if (ParameterSetName == "ById")
|
||||||
|
{
|
||||||
|
addressId = Id!.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addressId = AddressObject!.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var identifiers = new List<string> { addressId.ToString() };
|
||||||
|
var body = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
if (Gateway.HasValue)
|
||||||
|
body["is_gateway"] = Gateway.Value;
|
||||||
|
if (!string.IsNullOrEmpty(Description))
|
||||||
|
body["description"] = Description;
|
||||||
|
if (!string.IsNullOrEmpty(Hostname))
|
||||||
|
body["hostname"] = Hostname;
|
||||||
|
if (!string.IsNullOrEmpty(MAC))
|
||||||
|
body["mac"] = MAC;
|
||||||
|
if (!string.IsNullOrEmpty(Owner))
|
||||||
|
body["owner"] = Owner;
|
||||||
|
if (TagId.HasValue)
|
||||||
|
body["tag"] = TagId.Value;
|
||||||
|
if (PTRIgnore.HasValue)
|
||||||
|
body["PTRignore"] = PTRIgnore.Value;
|
||||||
|
if (PTRId.HasValue)
|
||||||
|
body["PTR"] = PTRId.Value;
|
||||||
|
if (!string.IsNullOrEmpty(Note))
|
||||||
|
body["note"] = Note;
|
||||||
|
if (ExcludePing.HasValue)
|
||||||
|
body["excludePing"] = ExcludePing.Value;
|
||||||
|
if (DeviceId.HasValue)
|
||||||
|
body["deviceId"] = DeviceId.Value;
|
||||||
|
if (!string.IsNullOrEmpty(Port))
|
||||||
|
body["port"] = Port;
|
||||||
|
|
||||||
|
if (CustomFields != null)
|
||||||
|
{
|
||||||
|
var customDict = ConvertCustomFields(CustomFields);
|
||||||
|
foreach (var kvp in customDict)
|
||||||
|
{
|
||||||
|
body[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, body, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (address != null)
|
||||||
|
{
|
||||||
|
WriteObject(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "SetAddressError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> ConvertCustomFields(object customFields)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object>();
|
||||||
|
if (customFields is PSObject psobj)
|
||||||
|
{
|
||||||
|
foreach (var prop in psobj.Properties)
|
||||||
|
{
|
||||||
|
dict[prop.Name] = prop.Value ?? new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (customFields is Dictionary<string, object> dictObj)
|
||||||
|
{
|
||||||
|
return dictObj;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
||||||
164
classlib/Cmdlets/SetSubnetCmdlet.cs
Normal file
164
classlib/Cmdlets/SetSubnetCmdlet.cs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
namespace PS.IPAM.Cmdlets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using PS.IPAM;
|
||||||
|
using PS.IPAM.Helpers;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Set, "Subnet")]
|
||||||
|
[OutputType(typeof(Subnetwork))]
|
||||||
|
public class SetSubnetCmdlet : PSCmdlet
|
||||||
|
{
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = true,
|
||||||
|
ValueFromPipeline = true,
|
||||||
|
ValueFromPipelineByPropertyName = true,
|
||||||
|
Position = 0)]
|
||||||
|
[ValidateNotNullOrEmpty]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? VlanId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? VrfId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? MasterSubnetId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? NameserverId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public SwitchParameter ShowName { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public SwitchParameter DNSRecursive { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public SwitchParameter DNSRecords { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public SwitchParameter AllowRequests { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? ScanAgentId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public SwitchParameter DiscoverSubnet { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public SwitchParameter IsFull { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? TagId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
[ValidateRange(1, 100)]
|
||||||
|
public int? Threshold { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public int? LocationId { get; set; }
|
||||||
|
|
||||||
|
[Parameter(
|
||||||
|
Mandatory = false)]
|
||||||
|
public object? CustomFields { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identifiers = new List<string> { Id.ToString() };
|
||||||
|
var body = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Description))
|
||||||
|
body["description"] = Description;
|
||||||
|
if (VlanId.HasValue)
|
||||||
|
body["vlanId"] = VlanId.Value;
|
||||||
|
if (VrfId.HasValue)
|
||||||
|
body["vrfId"] = VrfId.Value;
|
||||||
|
if (MasterSubnetId.HasValue)
|
||||||
|
body["masterSubnetId"] = MasterSubnetId.Value;
|
||||||
|
if (NameserverId.HasValue)
|
||||||
|
body["nameserverId"] = NameserverId.Value;
|
||||||
|
if (ShowName.IsPresent)
|
||||||
|
body["showName"] = "1";
|
||||||
|
if (DNSRecursive.IsPresent)
|
||||||
|
body["DNSrecursive"] = "1";
|
||||||
|
if (DNSRecords.IsPresent)
|
||||||
|
body["DNSrecords"] = "1";
|
||||||
|
if (AllowRequests.IsPresent)
|
||||||
|
body["allowRequests"] = "1";
|
||||||
|
if (ScanAgentId.HasValue)
|
||||||
|
body["scanAgent"] = ScanAgentId.Value;
|
||||||
|
if (DiscoverSubnet.IsPresent)
|
||||||
|
body["discoverSubnet"] = "1";
|
||||||
|
if (IsFull.IsPresent)
|
||||||
|
body["isFull"] = "1";
|
||||||
|
if (TagId.HasValue)
|
||||||
|
body["state"] = TagId.Value;
|
||||||
|
if (Threshold.HasValue)
|
||||||
|
body["threshold"] = Threshold.Value;
|
||||||
|
if (LocationId.HasValue)
|
||||||
|
body["location"] = LocationId.Value;
|
||||||
|
|
||||||
|
if (CustomFields != null)
|
||||||
|
{
|
||||||
|
var customDict = ConvertCustomFields(CustomFields);
|
||||||
|
foreach (var kvp in customDict)
|
||||||
|
{
|
||||||
|
body[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestHelper.InvokeRequest("PATCH", controllers.subnets, null, null, body, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, identifiers.ToArray())
|
||||||
|
.GetAwaiter().GetResult();
|
||||||
|
if (subnet != null)
|
||||||
|
{
|
||||||
|
WriteObject(subnet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteError(new ErrorRecord(ex, "SetSubnetError", ErrorCategory.InvalidOperation, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> ConvertCustomFields(object customFields)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object>();
|
||||||
|
if (customFields is PSObject psobj)
|
||||||
|
{
|
||||||
|
foreach (var prop in psobj.Properties)
|
||||||
|
{
|
||||||
|
dict[prop.Name] = prop.Value ?? new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (customFields is Dictionary<string, object> dictObj)
|
||||||
|
{
|
||||||
|
return dictObj;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
||||||
374
classlib/Helpers/RequestHelper.cs
Normal file
374
classlib/Helpers/RequestHelper.cs
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
namespace PS.IPAM.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using PS.IPAM;
|
||||||
|
|
||||||
|
public static class RequestHelper
|
||||||
|
{
|
||||||
|
// Handler for testing - allows injecting a mock HTTP handler
|
||||||
|
public static HttpMessageHandler? TestHttpHandler { get; set; }
|
||||||
|
|
||||||
|
public static async Task<object?> InvokeRequest(
|
||||||
|
string method,
|
||||||
|
controllers controller,
|
||||||
|
types? type = null,
|
||||||
|
subcontrollers? subController = null,
|
||||||
|
object? parameters = null,
|
||||||
|
string[]? identifiers = null,
|
||||||
|
bool ignoreSsl = false)
|
||||||
|
{
|
||||||
|
var tokenStatus = SessionManager.TestSession();
|
||||||
|
if (tokenStatus == "NoToken")
|
||||||
|
{
|
||||||
|
throw new Exception("No session available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenStatus == "Expired")
|
||||||
|
{
|
||||||
|
await UpdateSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
var session = SessionManager.CurrentSession;
|
||||||
|
if (session == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No session available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var uri = $"{session.URL}/api/{session.AppID}/{controller}";
|
||||||
|
if (subController != null)
|
||||||
|
{
|
||||||
|
uri += $"/{subController}";
|
||||||
|
}
|
||||||
|
if (identifiers != null && identifiers.Length > 0)
|
||||||
|
{
|
||||||
|
uri += $"/{string.Join("/", identifiers)}/";
|
||||||
|
}
|
||||||
|
|
||||||
|
using var client = SessionManager.CreateHttpClient(ignoreSsl, TestHttpHandler);
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
|
||||||
|
switch (session.AuthType)
|
||||||
|
{
|
||||||
|
case AuthType.credentials:
|
||||||
|
client.DefaultRequestHeaders.Add("token", session.Token);
|
||||||
|
break;
|
||||||
|
case AuthType.token:
|
||||||
|
client.DefaultRequestHeaders.Add("phpipam-token", session.Token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponseMessage? response = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (method == "GET")
|
||||||
|
{
|
||||||
|
response = await client.GetAsync(uri);
|
||||||
|
}
|
||||||
|
else if (method == "POST")
|
||||||
|
{
|
||||||
|
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
|
||||||
|
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||||
|
response = await client.PostAsync(uri, content);
|
||||||
|
}
|
||||||
|
else if (method == "PATCH")
|
||||||
|
{
|
||||||
|
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
|
||||||
|
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||||
|
var request = new HttpRequestMessage(new HttpMethod("PATCH"), uri)
|
||||||
|
{
|
||||||
|
Content = content
|
||||||
|
};
|
||||||
|
response = await client.SendAsync(request);
|
||||||
|
}
|
||||||
|
else if (method == "DELETE")
|
||||||
|
{
|
||||||
|
response = await client.DeleteAsync(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw new HttpRequestException($"Request failed with status {response.StatusCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(responseContent))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(responseContent);
|
||||||
|
if (jsonResponse == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.HasValue)
|
||||||
|
{
|
||||||
|
return ConvertToTypedObjects(jsonResponse, type.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonResponse.data;
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
if (ex.Message.Contains("404"))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? ConvertToTypedObjects(dynamic jsonResponse, types type)
|
||||||
|
{
|
||||||
|
if (jsonResponse?.data == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = jsonResponse.data;
|
||||||
|
if (data is JArray array)
|
||||||
|
{
|
||||||
|
return array.Select(item => ConvertSingleObject(item, type)).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ConvertSingleObject(data, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? ConvertSingleObject(dynamic item, types type)
|
||||||
|
{
|
||||||
|
var jobject = item as JObject;
|
||||||
|
if (jobject == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var customFields = new Dictionary<string, object>();
|
||||||
|
foreach (var prop in jobject.Properties())
|
||||||
|
{
|
||||||
|
if (prop.Name.StartsWith("custom_"))
|
||||||
|
{
|
||||||
|
customFields[prop.Name] = prop.Value?.ToObject<object>() ?? new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case types.Address:
|
||||||
|
return CreateAddress(jobject, customFields);
|
||||||
|
case types.Vlan:
|
||||||
|
return CreateVlan(jobject, customFields);
|
||||||
|
case types.Subnetwork:
|
||||||
|
return CreateSubnetwork(jobject, customFields);
|
||||||
|
case types.Vrf:
|
||||||
|
return CreateVrf(jobject, customFields);
|
||||||
|
case types.Section:
|
||||||
|
return CreateSection(jobject);
|
||||||
|
case types.Tag:
|
||||||
|
return CreateTag(jobject);
|
||||||
|
case types.Nameserver:
|
||||||
|
return CreateNameserver(jobject);
|
||||||
|
case types.Domain:
|
||||||
|
return CreateDomain(jobject);
|
||||||
|
default:
|
||||||
|
return jobject.ToObject<object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Address CreateAddress(JObject jobject, Dictionary<string, object> customFields)
|
||||||
|
{
|
||||||
|
return new Address(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["subnetId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["ip"]?.ToString() ?? "",
|
||||||
|
jobject["is_gateway"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["hostname"]?.ToString() ?? "",
|
||||||
|
jobject["mac"]?.ToString() ?? "",
|
||||||
|
jobject["owner"]?.ToString() ?? "",
|
||||||
|
jobject["tag"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["deviceId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["location"]?.ToString() ?? "",
|
||||||
|
jobject["port"]?.ToString() ?? "",
|
||||||
|
jobject["note"]?.ToString() ?? "",
|
||||||
|
jobject["lastSeen"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["excludePing"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["PTRignore"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["PTR"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["firewallAddressObject"]?.ToString() ?? "",
|
||||||
|
jobject["editDate"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["customer_id"]?.ToObject<int>() ?? 0,
|
||||||
|
customFields.Count > 0 ? customFields : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vlan CreateVlan(JObject jobject, Dictionary<string, object> customFields)
|
||||||
|
{
|
||||||
|
return new Vlan(
|
||||||
|
jobject["vlanId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["domainId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["name"]?.ToString() ?? "",
|
||||||
|
jobject["number"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["editDate"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["customer_id"]?.ToObject<int>() ?? 0,
|
||||||
|
customFields.Count > 0 ? customFields : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Subnetwork CreateSubnetwork(JObject jobject, Dictionary<string, object> customFields)
|
||||||
|
{
|
||||||
|
var props = jobject.Properties().ToList();
|
||||||
|
return new Subnetwork(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["subnet"]?.ToString() ?? "",
|
||||||
|
jobject["mask"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["sectionId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["linked_subnet"]?.ToString() ?? "",
|
||||||
|
jobject["firewallAddressObject"]?.ToString() ?? "",
|
||||||
|
jobject["vrfId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["masterSubnetId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["allowRequests"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["vlanId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["showName"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["deviceId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["permissions"]?.ToString() ?? "",
|
||||||
|
jobject["pingSubnet"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["discoverSubnet"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["resolveDNS"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["DNSrecursive"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["DNSrecords"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["nameserverId"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["scanAgent"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["isFolder"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["isFull"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["isPool"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["state"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["threshold"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["location"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["editDate"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["lastScan"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["lastDiscovery"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["calculation"]?.ToObject<object>() ?? new object(),
|
||||||
|
customFields.Count > 0 ? customFields : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vrf CreateVrf(JObject jobject, Dictionary<string, object> customFields)
|
||||||
|
{
|
||||||
|
return new Vrf(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["name"]?.ToString() ?? "",
|
||||||
|
jobject["rd"]?.ToString() ?? "",
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["sections"]?.ToString() ?? "",
|
||||||
|
jobject["editDate"]?.ToObject<DateTime?>(),
|
||||||
|
customFields.Count > 0 ? customFields : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Section CreateSection(JObject jobject)
|
||||||
|
{
|
||||||
|
return new Section(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["name"]?.ToString() ?? "",
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["masterSection"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["permissions"]?.ToString() ?? "",
|
||||||
|
jobject["strictMode"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["subnetOrdering"]?.ToString() ?? "",
|
||||||
|
jobject["order"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["editDate"]?.ToObject<DateTime?>(),
|
||||||
|
jobject["showSubnet"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["showVlan"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["showVRF"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["showSupernetOnly"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["DNS"]?.ToObject<int>() ?? 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Tag CreateTag(JObject jobject)
|
||||||
|
{
|
||||||
|
return new Tag(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["type"]?.ToString() ?? "",
|
||||||
|
jobject["showtag"]?.ToObject<bool>() ?? false,
|
||||||
|
jobject["bgcolor"]?.ToString() ?? "",
|
||||||
|
jobject["fgcolor"]?.ToString() ?? "",
|
||||||
|
jobject["compress"]?.ToString() ?? "",
|
||||||
|
jobject["locked"]?.ToString() ?? "",
|
||||||
|
jobject["updateTag"]?.ToObject<bool>() ?? false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Nameserver CreateNameserver(JObject jobject)
|
||||||
|
{
|
||||||
|
return new Nameserver(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["name"]?.ToString() ?? "",
|
||||||
|
jobject["nameservers"]?.ToString() ?? "",
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["permissions"]?.ToString() ?? "",
|
||||||
|
jobject["editDate"]?.ToObject<DateTime?>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Domain CreateDomain(JObject jobject)
|
||||||
|
{
|
||||||
|
return new Domain(
|
||||||
|
jobject["id"]?.ToObject<int>() ?? 0,
|
||||||
|
jobject["name"]?.ToString() ?? "",
|
||||||
|
jobject["description"]?.ToString() ?? "",
|
||||||
|
jobject["sections"]?.ToString() ?? ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task UpdateSession()
|
||||||
|
{
|
||||||
|
var session = SessionManager.CurrentSession;
|
||||||
|
if (session == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No session available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenStatus = SessionManager.TestSession();
|
||||||
|
if (tokenStatus == "Valid")
|
||||||
|
{
|
||||||
|
// Just refresh the token
|
||||||
|
var result = await InvokeRequest("PATCH", controllers.user, null, null, null, null);
|
||||||
|
// Token refresh doesn't return expires in the same format, so we'll skip updating expires
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenStatus == "Expired" && session.Credentials is PSCredential creds)
|
||||||
|
{
|
||||||
|
await SessionManager.CreateSessionWithCredentials(
|
||||||
|
session.URL,
|
||||||
|
session.AppID,
|
||||||
|
creds,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
classlib/Helpers/SessionManager.cs
Normal file
131
classlib/Helpers/SessionManager.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
namespace PS.IPAM.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PS.IPAM;
|
||||||
|
|
||||||
|
public static class SessionManager
|
||||||
|
{
|
||||||
|
private static Session? _currentSession;
|
||||||
|
|
||||||
|
public static Session? CurrentSession
|
||||||
|
{
|
||||||
|
get => _currentSession;
|
||||||
|
set => _currentSession = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string TestSession()
|
||||||
|
{
|
||||||
|
if (_currentSession == null)
|
||||||
|
{
|
||||||
|
return "NoToken";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentSession.Expires == null)
|
||||||
|
{
|
||||||
|
return "Valid";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentSession.Expires < DateTime.Now)
|
||||||
|
{
|
||||||
|
return "Expired";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Valid";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Session> CreateSessionWithCredentials(
|
||||||
|
string url,
|
||||||
|
string appId,
|
||||||
|
PSCredential credentials,
|
||||||
|
bool ignoreSsl = false)
|
||||||
|
{
|
||||||
|
var uri = $"{url}/api/{appId}/user";
|
||||||
|
var auth = Convert.ToBase64String(
|
||||||
|
Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPassword(credentials)}"));
|
||||||
|
|
||||||
|
using var client = CreateHttpClient(ignoreSsl);
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
|
||||||
|
|
||||||
|
var response = await client.PostAsync(uri, null);
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(content);
|
||||||
|
|
||||||
|
if (jsonResponse?.success != true)
|
||||||
|
{
|
||||||
|
throw new Exception(jsonResponse?.error?.ToString() ?? "Failed to create session");
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = jsonResponse.data.token.ToString();
|
||||||
|
var expires = DateTime.Parse(jsonResponse.data.expires.ToString());
|
||||||
|
|
||||||
|
_currentSession = new Session(
|
||||||
|
AuthType.credentials,
|
||||||
|
token,
|
||||||
|
appId,
|
||||||
|
url,
|
||||||
|
expires,
|
||||||
|
credentials
|
||||||
|
);
|
||||||
|
|
||||||
|
return _currentSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Session CreateSessionWithToken(
|
||||||
|
string url,
|
||||||
|
string appId,
|
||||||
|
string token)
|
||||||
|
{
|
||||||
|
_currentSession = new Session(
|
||||||
|
AuthType.token,
|
||||||
|
token,
|
||||||
|
appId,
|
||||||
|
url,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
return _currentSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CloseSession()
|
||||||
|
{
|
||||||
|
_currentSession = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetPassword(PSCredential credential)
|
||||||
|
{
|
||||||
|
var ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(credential.Password);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null)
|
||||||
|
{
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
return new HttpClient(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreSsl)
|
||||||
|
{
|
||||||
|
var sslHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
|
||||||
|
};
|
||||||
|
return new HttpClient(sslHandler);
|
||||||
|
}
|
||||||
|
return new HttpClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ public class Address {
|
|||||||
this.Location = location;
|
this.Location = location;
|
||||||
this.Port = port;
|
this.Port = port;
|
||||||
this.Note = note;
|
this.Note = note;
|
||||||
this.EditDate = lastSeen;
|
this.LastSeen = lastSeen;
|
||||||
this.ExcludePing = excludePing;
|
this.ExcludePing = excludePing;
|
||||||
this.PTRignore = PTRignore;
|
this.PTRignore = PTRignore;
|
||||||
this.PTR = PTR;
|
this.PTR = PTR;
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
namespace PS.IPAM;
|
namespace PS.IPAM;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Management.Automation;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Session {
|
public class Session {
|
||||||
public AuthType AuthType { get; }
|
public AuthType AuthType { get; }
|
||||||
public string Token { get; }
|
public string Token { get; set; }
|
||||||
public string AppID { get; }
|
public string AppID { get; }
|
||||||
public string URL { get; }
|
public string URL { get; }
|
||||||
public DateTime? Expires { get; }
|
public DateTime? Expires { get; set; }
|
||||||
public Object? Credentials { get; }
|
public object? Credentials { get; }
|
||||||
public Session(
|
public Session(
|
||||||
AuthType authType,
|
AuthType authType,
|
||||||
string token,
|
string token,
|
||||||
string appId,
|
string appId,
|
||||||
string url,
|
string url,
|
||||||
DateTime? expires,
|
DateTime? expires,
|
||||||
Object? credentials
|
object? credentials
|
||||||
) {
|
) {
|
||||||
AuthType = authType;
|
AuthType = authType;
|
||||||
Token = token;
|
Token = token;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Dynamic;
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class Vlan : DynamicObject {
|
public class Vlan : DynamicObject {
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
|
public int VlanId { get; }
|
||||||
public int DomainId { get; }
|
public int DomainId { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public int Number { get; }
|
public int Number { get; }
|
||||||
@@ -23,6 +24,7 @@ public class Vlan : DynamicObject {
|
|||||||
Object? custom_fields
|
Object? custom_fields
|
||||||
) {
|
) {
|
||||||
this.Id = vlanId;
|
this.Id = vlanId;
|
||||||
|
this.VlanId = vlanId;
|
||||||
this.DomainId = domainId;
|
this.DomainId = domainId;
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Number = number;
|
this.Number = number;
|
||||||
|
|||||||
@@ -5,6 +5,14 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
|
<AssemblyName>ps.ipam</AssemblyName>
|
||||||
|
<RootNamespace>PS.IPAM</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
@{
|
@{
|
||||||
RootModule = 'ps.ipam.psm1'
|
RootModule = 'ps.ipam.dll'
|
||||||
ModuleVersion = '2.0'
|
ModuleVersion = '2.0'
|
||||||
GUID = 'cd573493-4245-4073-a238-fab2251d78d0'
|
GUID = 'cd573493-4245-4073-a238-fab2251d78d0'
|
||||||
Author = 'Nikolay Tatarinov'
|
Author = 'Nikolay Tatarinov'
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
PowerShellVersion = '5.1'
|
PowerShellVersion = '5.1'
|
||||||
|
|
||||||
RequiredAssemblies = @(
|
RequiredAssemblies = @(
|
||||||
'classlib\bin\Release\netstandard2.1\publish\classlib.dll'
|
'ps.ipam.dll'
|
||||||
)
|
)
|
||||||
|
|
||||||
TypesToProcess = @(
|
TypesToProcess = @(
|
||||||
'types\types.ps1xml'
|
'types\types.ps1xml'
|
||||||
)
|
)
|
||||||
|
|
||||||
FunctionsToExport = @(
|
CmdletsToExport = @(
|
||||||
'Assign-Tag',
|
'Assign-Tag',
|
||||||
'Close-Session',
|
'Close-Session',
|
||||||
'New-Session',
|
'New-Session',
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
'New-Address',
|
'New-Address',
|
||||||
'New-FirstFreeIP',
|
'New-FirstFreeIP',
|
||||||
'Set-Address',
|
'Set-Address',
|
||||||
|
'Set-Subnet',
|
||||||
'Remove-Address'
|
'Remove-Address'
|
||||||
)
|
)
|
||||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||||
|
|||||||
Reference in New Issue
Block a user