package main import ( "context" "fmt" "isle/bootstrap" "isle/daemon" "isle/daemon/daecommon" "isle/nebula" "isle/toolkit" "net/netip" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNetworkCreate(t *testing.T) { t.Parallel() tests := []struct { name string expect func(*testing.T, *daemon.MockRPC) flags []string }{ { name: "no given config", expect: func(t *testing.T, daemonRPC *daemon.MockRPC) { daemonRPC. On( "CreateNetwork", toolkit.MockArg[context.Context](), bootstrapNewCreationParams("aaa", "a.com"), nebula.MustParseIPNet(t, "172.16.1.0/24"), nebula.HostName("foo"), &daemon.CreateNetworkOpts{}, ). Return(nil). Once() }, flags: []string{ "--name=aaa", "--domain=a.com", "--ip-net=172.16.1.0/24", "--hostname=foo", }, }, { name: "partially given config", expect: func(t *testing.T, daemonRPC *daemon.MockRPC) { networkConfig := daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) { c.VPN.PublicAddr = "1.2.3.4:5" }) daemonRPC. On( "CreateNetwork", toolkit.MockArg[context.Context](), bootstrapNewCreationParams("aaa", "a.com"), nebula.MustParseIPNet(t, "172.16.1.0/24"), nebula.HostName("foo"), &daemon.CreateNetworkOpts{ Config: &networkConfig, }, ). Return(nil). Once() }, flags: []string{ "--name=aaa", "--domain=a.com", "--ip-net=172.16.1.0/24", "--hostname=foo", "--vpn-public-address=1.2.3.4:5", }, }, { name: "fully given config", expect: func(t *testing.T, daemonRPC *daemon.MockRPC) { networkConfig := daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) { c.VPN.PublicAddr = "1.2.3.4:5" c.Storage.Allocations = []daecommon.ConfigStorageAllocation{ { DataPath: "/a/data", MetaPath: "/a/meta", Capacity: 100, }, { DataPath: "/b/data", MetaPath: "/b/meta", Capacity: 200, }, } }) daemonRPC. On( "CreateNetwork", toolkit.MockArg[context.Context](), bootstrapNewCreationParams("aaa", "a.com"), nebula.MustParseIPNet(t, "172.16.1.0/24"), nebula.HostName("foo"), &daemon.CreateNetworkOpts{ Config: &networkConfig, }, ). Return(nil). Once() }, flags: []string{ "--name=aaa", "--domain=a.com", "--ip-net=172.16.1.0/24", "--hostname=foo", "--vpn-public-address=1.2.3.4:5", "--storage-allocation=100@/a", "--storage-allocation=200@/b", }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { var ( h = newRunHarness(t) args = append([]string{"network", "create"}, test.flags...) ) test.expect(t, h.daemonRPC) assert.NoError(t, h.run(t, args...)) }) } } func TestNetworkList(t *testing.T) { t.Parallel() type networkBase struct { bootstrap.CreationParams ipNet nebula.IPNet caCreds nebula.CACredentials caCertPEM string } newNetworkBase := func(id, name, domain, ipNetStr string) networkBase { var ipNet nebula.IPNet require.NoError(t, ipNet.UnmarshalText([]byte(ipNetStr))) caCreds, err := nebula.NewCACredentials(domain, ipNet) require.NoError(t, err) caCertPEM, err := caCreds.Public.Cert.MarshalText() require.NoError(t, err) return networkBase{ CreationParams: bootstrap.CreationParams{ ID: id, Name: name, Domain: domain, }, ipNet: ipNet, caCreds: caCreds, caCertPEM: string(caCertPEM), } } var ( networkBaseA = newNetworkBase("idA", "nameA", "a.com", "172.16.1.0/24") networkBaseB = newNetworkBase("idB", "nameB", "b.com", "172.16.2.0/24") ) type host struct { ip string publicAddr string } type network struct { networkBase hosts []host } tests := []struct { name string networks []network want []map[string]any }{ { name: "no networks", want: []map[string]any{}, }, { name: "single", networks: []network{ { networkBase: networkBaseA, hosts: []host{ { ip: "172.16.1.1", publicAddr: "1.1.1.1:80", }, }, }, }, want: []map[string]any{ { "id": "idA", "name": "nameA", "domain": "a.com", "ca_cert": networkBaseA.caCertPEM, "subnet_cidr": "172.16.1.0/24", "lighthouses": []any{ map[string]any{ "ip": "172.16.1.1", "public_addr": "1.1.1.1:80", }, }, }, }, }, { name: "multiple", networks: []network{ { networkBase: networkBaseB, hosts: []host{ { ip: "172.16.2.1", publicAddr: "2.2.2.2:80", }, { ip: "172.16.2.2", publicAddr: "3.3.3.3:80", }, { ip: "172.16.2.3", }, }, }, { networkBase: networkBaseA, hosts: []host{ { ip: "172.16.1.1", publicAddr: "1.1.1.1:80", }, }, }, }, want: []map[string]any{ { "id": "idA", "name": "nameA", "domain": "a.com", "ca_cert": networkBaseA.caCertPEM, "subnet_cidr": "172.16.1.0/24", "lighthouses": []any{ map[string]any{ "ip": "172.16.1.1", "public_addr": "1.1.1.1:80", }, }, }, { "id": "idB", "name": "nameB", "domain": "b.com", "ca_cert": networkBaseB.caCertPEM, "subnet_cidr": "172.16.2.0/24", "lighthouses": []any{ map[string]any{ "ip": "172.16.2.1", "public_addr": "2.2.2.2:80", }, map[string]any{ "ip": "172.16.2.2", "public_addr": "3.3.3.3:80", }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { var ( h = newRunHarness(t) creationParams = make([]bootstrap.CreationParams, len(test.networks)) ) for i, testNetwork := range test.networks { creationParams[i] = testNetwork.CreationParams hosts := map[nebula.HostName]bootstrap.Host{} for _, testHost := range testNetwork.hosts { var ( hostName nebula.HostName ip = netip.MustParseAddr(testHost.ip) hostNameStr = fmt.Sprintf("host%d", len(hosts)) ) require.NoError( t, hostName.UnmarshalText([]byte(hostNameStr)), ) host, _, err := bootstrap.NewHost( testNetwork.caCreds, hostName, ip, ) require.NoError(t, err) host.Nebula.PublicAddr = testHost.publicAddr hosts[hostName] = host } h.daemonRPC. On( "GetBootstrap", daemon.MockContextWithNetwork(testNetwork.ID), ). Return(bootstrap.Bootstrap{ NetworkCreationParams: creationParams[i], CAPublicCredentials: testNetwork.caCreds.Public, Hosts: hosts, }, nil). Once() } h.daemonRPC. On("GetNetworks", toolkit.MockArg[context.Context]()). Return(creationParams, nil). Once() h.runAssertStdout(t, test.want, "network", "list") }) } }