diff --git a/hcn/hcnendpoint_test.go b/hcn/hcnendpoint_test.go index 49228cd6a5..e20dba659a 100644 --- a/hcn/hcnendpoint_test.go +++ b/hcn/hcnendpoint_test.go @@ -9,7 +9,7 @@ import ( ) func TestCreateDeleteEndpoint(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -34,7 +34,7 @@ func TestCreateDeleteEndpoint(t *testing.T) { } func TestGetEndpointById(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -62,7 +62,7 @@ func TestGetEndpointById(t *testing.T) { } func TestGetEndpointByName(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -90,7 +90,7 @@ func TestGetEndpointByName(t *testing.T) { } func TestListEndpoints(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -118,7 +118,7 @@ func TestListEndpoints(t *testing.T) { } func TestListEndpointsOfNetwork(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -146,7 +146,7 @@ func TestListEndpointsOfNetwork(t *testing.T) { } func TestEndpointNamespaceAttachDetach(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -183,7 +183,7 @@ func TestEndpointNamespaceAttachDetach(t *testing.T) { } func TestCreateEndpointWithNamespace(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -210,7 +210,7 @@ func TestCreateEndpointWithNamespace(t *testing.T) { } func TestApplyPolicyOnEndpoint(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -251,7 +251,7 @@ func TestApplyPolicyOnEndpoint(t *testing.T) { } func TestModifyEndpointSettings(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } diff --git a/hcn/hcnloadbalancer_test.go b/hcn/hcnloadbalancer_test.go index 0d51625e0a..e06b337a50 100644 --- a/hcn/hcnloadbalancer_test.go +++ b/hcn/hcnloadbalancer_test.go @@ -9,7 +9,7 @@ import ( ) func TestCreateDeleteLoadBalancer(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -42,7 +42,7 @@ func TestCreateDeleteLoadBalancer(t *testing.T) { } func TestGetLoadBalancerById(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -83,7 +83,7 @@ func TestListLoadBalancer(t *testing.T) { } func TestLoadBalancerAddRemoveEndpoint(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -135,7 +135,7 @@ func TestLoadBalancerAddRemoveEndpoint(t *testing.T) { } func TestAddLoadBalancer(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -171,7 +171,7 @@ func TestAddLoadBalancer(t *testing.T) { } func TestAddDSRLoadBalancer(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := CreateTestOverlayNetwork() if err != nil { t.Fatal(err) } @@ -207,7 +207,7 @@ func TestAddDSRLoadBalancer(t *testing.T) { } func TestAddILBLoadBalancer(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := CreateTestOverlayNetwork() if err != nil { t.Fatal(err) } diff --git a/hcn/hcnnamespace_test.go b/hcn/hcnnamespace_test.go index 7028f0c454..9aa6fab9e5 100644 --- a/hcn/hcnnamespace_test.go +++ b/hcn/hcnnamespace_test.go @@ -97,7 +97,7 @@ func TestListNamespaces(t *testing.T) { } func TestGetNamespaceEndpointIds(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -161,7 +161,7 @@ func TestGetNamespaceContainers(t *testing.T) { } func TestAddRemoveNamespaceEndpoint(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -205,7 +205,7 @@ func TestAddRemoveNamespaceEndpoint(t *testing.T) { } func TestModifyNamespaceSettings(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } diff --git a/hcn/hcnnetwork.go b/hcn/hcnnetwork.go index fd91da08d8..45c876e246 100644 --- a/hcn/hcnnetwork.go +++ b/hcn/hcnnetwork.go @@ -75,6 +75,30 @@ type HostComputeNetwork struct { SchemaVersion SchemaVersion `json:",omitempty"` } +// NetworkResourceType are the 3 different Network settings resources. +type NetworkResourceType string + +var ( + // NetworkResourceTypePolicy is for Network's policies. Ex: RemoteSubnet + NetworkResourceTypePolicy NetworkResourceType = "Policy" + // NetworkResourceTypeDNS is for Network's DNS settings. + NetworkResourceTypeDNS NetworkResourceType = "DNS" + // NetworkResourceTypeExtension is for Network's extension settings. + NetworkResourceTypeExtension NetworkResourceType = "Extension" +) + +// ModifyNetworkSettingRequest is the structure used to send request to modify an network. +// Used to update DNS/extension/policy on an network. +type ModifyNetworkSettingRequest struct { + ResourceType NetworkResourceType `json:",omitempty"` // Policy, DNS, Extension + RequestType RequestType `json:",omitempty"` // Add, Remove, Update, Refresh + Settings json.RawMessage `json:",omitempty"` +} + +type PolicyNetworkRequest struct { + Policies []NetworkPolicy `json:",omitempty"` +} + func getNetwork(networkGuid guid.GUID, query string) (*HostComputeNetwork, error) { // Open network. var ( @@ -311,6 +335,56 @@ func (network *HostComputeNetwork) Delete() (*HostComputeNetwork, error) { return nil, nil } +// ModifyNetworkSettings updates the Policy for a network. +func (network *HostComputeNetwork) ModifyNetworkSettings(request *ModifyNetworkSettingRequest) error { + logrus.Debugf("hcn::HostComputeNetwork::ModifyNetworkSettings id=%s", network.Id) + + networkSettingsRequest, err := json.Marshal(request) + if err != nil { + return err + } + + _, err = modifyNetwork(network.Id, string(networkSettingsRequest)) + if err != nil { + return err + } + return nil +} + +// AddPolicy applies a Policy (ex: RemoteSubnet) on the Network. +func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error { + logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id) + + settingsJson, err := json.Marshal(networkPolicy) + if err != nil { + return err + } + requestMessage := &ModifyNetworkSettingRequest{ + ResourceType: NetworkResourceTypePolicy, + RequestType: RequestTypeAdd, + Settings: settingsJson, + } + + return network.ModifyNetworkSettings(requestMessage) +} + +// RemovePolicy removes a Policy (ex: RemoteSubnet) from the Network. +func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error { + logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id) + + settingsJson, err := json.Marshal(networkPolicy) + if err != nil { + return err + } + requestMessage := &ModifyNetworkSettingRequest{ + ResourceType: NetworkResourceTypePolicy, + RequestType: RequestTypeRemove, + Settings: settingsJson, + } + + return network.ModifyNetworkSettings(requestMessage) +} + // CreateEndpoint creates an endpoint on the Network. func (network *HostComputeNetwork) CreateEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) { isRemote := endpoint.Flags&EndpointFlagsRemoteEndpoint != 0 diff --git a/hcn/hcnnetwork_test.go b/hcn/hcnnetwork_test.go index a37d7edfd5..a773bb6938 100644 --- a/hcn/hcnnetwork_test.go +++ b/hcn/hcnnetwork_test.go @@ -9,7 +9,7 @@ import ( ) func TestCreateDeleteNetwork(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -25,7 +25,7 @@ func TestCreateDeleteNetwork(t *testing.T) { } func TestGetNetworkByName(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -43,7 +43,7 @@ func TestGetNetworkByName(t *testing.T) { } func TestGetNetworkById(t *testing.T) { - network, err := HcnCreateTestNetwork() + network, err := HcnCreateTestNATNetwork() if err != nil { t.Fatal(err) } @@ -66,3 +66,61 @@ func TestListNetwork(t *testing.T) { t.Fatal(err) } } + +func TestAddRemoveRemoteSubnetRoutePolicy(t *testing.T) { + + network, err := CreateTestOverlayNetwork() + if err != nil { + t.Fatal(err) + } + + remoteSubnetRoutePolicy, err := HcnCreateTestRemoteSubnetRoute() + if err != nil { + t.Fatal(err) + } + + //Add Policy + network.AddPolicy(*remoteSubnetRoutePolicy) + + //Reload the network object from HNS. + network, err = GetNetworkByID(network.Id) + if err != nil { + t.Fatal(err) + } + + foundPolicy := false + for _, policy := range network.Policies { + if policy.Type == RemoteSubnetRoute { + foundPolicy = true + break + } + } + if !foundPolicy { + t.Fatalf("Could not find remote subnet route policy on network.") + } + + //Remove Policy. + network.RemovePolicy(*remoteSubnetRoutePolicy) + + //Reload the network object from HNS. + network, err = GetNetworkByID(network.Id) + if err != nil { + t.Fatal(err) + } + + foundPolicy = false + for _, policy := range network.Policies { + if policy.Type == RemoteSubnetRoute { + foundPolicy = true + break + } + } + if foundPolicy { + t.Fatalf("Found remote subnet route policy on network when it should have been deleted.") + } + + _, err = network.Delete() + if err != nil { + t.Fatal(err) + } +} diff --git a/hcn/hcnpolicy.go b/hcn/hcnpolicy.go index 1511028929..70442e191b 100644 --- a/hcn/hcnpolicy.go +++ b/hcn/hcnpolicy.go @@ -39,6 +39,7 @@ const ( AutomaticDNS NetworkPolicyType = "AutomaticDNS" InterfaceConstraint NetworkPolicyType = "InterfaceConstraint" ProviderAddress NetworkPolicyType = "ProviderAddress" + RemoteSubnetRoute NetworkPolicyType = "RemoteSubnetRoute" ) // NetworkPolicy is a collection of Policy settings for a Network. @@ -205,3 +206,11 @@ type VlanPolicySetting struct { type VsidPolicySetting struct { IsolationId uint32 `json:","` } + +// RemoteSubnetRoutePolicySetting creates remote subnet route rules on a network +type RemoteSubnetRoutePolicySetting struct { + DestinationPrefix string + IsolationId uint16 + ProviderAddress string + DistributedRouterMacAddress string +} diff --git a/hcn/hcnutils_test.go b/hcn/hcnutils_test.go index b02a3b82bf..0fbe566ce2 100644 --- a/hcn/hcnutils_test.go +++ b/hcn/hcnutils_test.go @@ -6,9 +6,9 @@ import ( "encoding/json" ) -func cleanup() { +func cleanup(networkName string) { // Delete test network (if exists) - testNetwork, err := GetNetworkByName(NatTestNetworkName) + testNetwork, err := GetNetworkByName(networkName) if err != nil { return } @@ -20,8 +20,8 @@ func cleanup() { } } -func HcnCreateTestNetwork() (*HostComputeNetwork, error) { - cleanup() +func HcnCreateTestNATNetwork() (*HostComputeNetwork, error) { + cleanup(NatTestNetworkName) network := &HostComputeNetwork{ Type: "NAT", Name: NatTestNetworkName, @@ -58,6 +58,64 @@ func HcnCreateTestNetwork() (*HostComputeNetwork, error) { return network.Create() } +func CreateTestOverlayNetwork() (*HostComputeNetwork, error) { + cleanup(OverlayTestNetworkName) + network := &HostComputeNetwork{ + Type: "Overlay", + Name: OverlayTestNetworkName, + MacPool: MacPool{ + Ranges: []MacRange{ + { + StartMacAddress: "00-15-5D-52-C0-00", + EndMacAddress: "00-15-5D-52-CF-FF", + }, + }, + }, + Ipams: []Ipam{ + { + Type: "Static", + Subnets: []Subnet{ + { + IpAddressPrefix: "192.168.100.0/24", + Routes: []Route{ + { + NextHop: "192.168.100.1", + DestinationPrefix: "0.0.0.0/0", + }, + }, + }, + }, + }, + }, + SchemaVersion: SchemaVersion{ + Major: 2, + Minor: 0, + }, + } + + vsid := &VsidPolicySetting{ + IsolationId: 5000, + } + vsidJson, err := json.Marshal(vsid) + if err != nil { + return nil, err + } + + sp := &SubnetPolicy{ + Type: VSID, + } + sp.Settings = vsidJson + + spJson, err := json.Marshal(sp) + if err != nil { + return nil, err + } + + network.Ipams[0].Subnets[0].Policies = append(network.Ipams[0].Subnets[0].Policies, spJson) + + return network.Create() +} + func HcnCreateTestEndpoint(network *HostComputeNetwork) (*HostComputeEndpoint, error) { if network == nil { @@ -169,3 +227,27 @@ func HcnCreateTestLoadBalancer(endpoint *HostComputeEndpoint) (*HostComputeLoadB return loadBalancer.Create() } + +func HcnCreateTestRemoteSubnetRoute() (*PolicyNetworkRequest, error) { + rsr := RemoteSubnetRoutePolicySetting{ + DestinationPrefix: "192.168.2.0/24", + IsolationId: 5000, + ProviderAddress: "1.1.1.1", + DistributedRouterMacAddress: "00-12-34-56-78-9a", + } + + rawJSON, err := json.Marshal(rsr) + if err != nil { + return nil, err + } + rsrPolicy := NetworkPolicy{ + Type: RemoteSubnetRoute, + Settings: rawJSON, + } + + networkRequest := PolicyNetworkRequest{ + Policies: []NetworkPolicy{rsrPolicy}, + } + + return &networkRequest, nil +} diff --git a/hcn/hcnv1schema_test.go b/hcn/hcnv1schema_test.go index 980785d0b0..a45d5cb1fd 100644 --- a/hcn/hcnv1schema_test.go +++ b/hcn/hcnv1schema_test.go @@ -10,7 +10,7 @@ import ( ) func TestV1Network(t *testing.T) { - cleanup() + cleanup(NatTestNetworkName) v1network := hcsshim.HNSNetwork{ Type: "NAT", @@ -49,7 +49,7 @@ func TestV1Network(t *testing.T) { } func TestV1Endpoint(t *testing.T) { - cleanup() + cleanup(NatTestNetworkName) v1network := hcsshim.HNSNetwork{ Type: "NAT", diff --git a/hcn/hnsv1_test.go b/hcn/hnsv1_test.go index d62da11dbe..e5a867474c 100644 --- a/hcn/hnsv1_test.go +++ b/hcn/hnsv1_test.go @@ -10,8 +10,9 @@ import ( ) const ( - NatTestNetworkName string = "GoTestNat" - NatTestEndpointName string = "GoTestNatEndpoint" + NatTestNetworkName string = "GoTestNat" + NatTestEndpointName string = "GoTestNatEndpoint" + OverlayTestNetworkName string = "GoTestOverlay" ) func TestMain(m *testing.M) {