diff --git a/netmaster/main.go b/netmaster/main.go index cc9bc6147..bc2d919b3 100644 --- a/netmaster/main.go +++ b/netmaster/main.go @@ -39,6 +39,7 @@ type cliOpts struct { storeURL string listenURL string clusterMode string + dnsEnabled bool version bool } @@ -107,6 +108,10 @@ func parseOpts(opts *cliOpts) error { "cluster-mode", "docker", "{docker, kubernetes}") + flagSet.BoolVar(&opts.dnsEnabled, + "dns-enable", + true, + "Turn on DNS {true, false}") flagSet.BoolVar(&opts.version, "version", false, @@ -142,6 +147,10 @@ func execOpts(opts *cliOpts) core.StateDriver { log.Fatalf("Failed to set cluster-mode. Error: %s", err) } + if err := master.SetDNSEnabled(opts.dnsEnabled); err != nil { + log.Fatalf("Failed to set dns-enable. Error: %s", err) + } + sd, err := initStateDriver(opts) if err != nil { log.Fatalf("Failed to init state-store. Error: %s", err) diff --git a/netmaster/master/netmaster.go b/netmaster/master/netmaster.go index 611392b5d..00c5307d5 100755 --- a/netmaster/master/netmaster.go +++ b/netmaster/master/netmaster.go @@ -38,6 +38,7 @@ const ( // Run Time config of netmaster type nmRunTimeConf struct { clusterMode string + dnsEnabled bool } var masterRTCfg nmRunTimeConf @@ -61,6 +62,22 @@ func GetClusterMode() string { return masterRTCfg.clusterMode } +// IsDNSEnabled gets the status of whether DNS is enabled +func IsDNSEnabled() bool { + return masterRTCfg.dnsEnabled +} + +// SetDNSEnabled sets the status of DNS Enable +func SetDNSEnabled(dnsEnableFlag bool) error { + log.Infof("Setting dns flag to %s", dnsEnableFlag) + masterRTCfg.dnsEnabled = dnsEnableFlag + return nil +} + +func getDNSName(tenantName string) string { + return tenantName + "dns" +} + func getEpName(networkName string, ep *intent.ConfigEP) string { if ep.Container != "" { return networkName + "-" + ep.Container @@ -196,12 +213,12 @@ func CreateTenant(stateDriver core.StateDriver, tenant *intent.ConfigTenant) err return err } - if GetClusterMode() == "docker" { + if IsDNSEnabled() { // start skydns container err = startServiceContainer(tenant.Name) if err != nil { - log.Errorf("Error starting service container. Err: %v", err) - return err + log.Errorf("Error starting service container. Err: %v. Disabling DNS option.", err) + SetDNSEnabled(false) } } @@ -243,13 +260,17 @@ func startServiceContainer(tenantName string) error { "SKYDNS_ADDR=0.0.0.0:53", "SKYDNS_DOMAIN=" + tenantName}} - containerID, err := docker.CreateContainer(containerConfig, tenantName+"dns", nil) + containerID, err := docker.CreateContainer(containerConfig, getDNSName(tenantName), nil) if err != nil { log.Errorf("Error creating DNS container for tenant: %s. Error: %s", tenantName, err) + return err } + hostConfig := &dockerclient.HostConfig{ + RestartPolicy: dockerclient.RestartPolicy{Name: "always"}} + // Start the container - err = docker.StartContainer(containerID, nil) + err = docker.StartContainer(containerID, hostConfig) if err != nil { log.Errorf("Error starting DNS container for tenant: %s. Error: %s", tenantName, err) } @@ -265,7 +286,7 @@ func stopAndRemoveServiceContainer(tenantName string) error { return err } - dnsContName := tenantName + "dns" + dnsContName := getDNSName(tenantName) // Stop the container err = docker.StopContainer(dnsContName, 10) if err != nil { @@ -283,7 +304,7 @@ func stopAndRemoveServiceContainer(tenantName string) error { // DeleteTenantID deletes a tenant from the state store, by ID. func DeleteTenantID(stateDriver core.StateDriver, tenantID string) error { - if GetClusterMode() == "docker" { + if IsDNSEnabled() { err := stopAndRemoveServiceContainer(tenantID) if err != nil { log.Errorf("Error in stopping service container for tenant: %+v", tenantID) diff --git a/netmaster/master/network.go b/netmaster/master/network.go index e9cbe9d4b..82567917f 100644 --- a/netmaster/master/network.go +++ b/netmaster/master/network.go @@ -17,7 +17,6 @@ package master import ( "errors" - "fmt" "net" "strings" @@ -148,7 +147,9 @@ func CreateNetwork(network intent.ConfigNetwork, stateDriver core.StateDriver, t log.Errorf("Error creating network %s in docker. Err: %v", nwCfg.ID, err) return err } + } + if IsDNSEnabled() { // Attach service container endpoint to the network err = attachServiceContainer(tenantName, network.Name, stateDriver) if err != nil { @@ -162,34 +163,66 @@ func CreateNetwork(network intent.ConfigNetwork, stateDriver core.StateDriver, t } func attachServiceContainer(tenantName, networkName string, stateDriver core.StateDriver) error { - contName := tenantName + "dns" + contName := getDNSName(tenantName) docker, err := utils.GetDockerClient() if err != nil { log.Errorf("Unable to connect to docker. Error %v", err) return err } + cinfo, err := docker.InspectContainer(contName) + if err != nil { + if strings.Contains(err.Error(), "no such id") { + // DNS container not started for this tenant. Start skydns container + err = startServiceContainer(tenantName) + if err != nil { + log.Warnf("Error starting service container. "+ + "Continuing without DNS provider. Error: %v", err) + return nil + } + cinfo, err = docker.InspectContainer(contName) + if err != nil { + log.Warnf("Error fetching container info after starting %s"+ + "Continuing without DNS provider. Error: %s", contName, err) + return nil + } + } + } + + // If it's not in running state, restart the container. + // This case can occur if the host is reloaded + if !cinfo.State.Running { + log.Debugf("Container %s not running. Restarting the container", contName) + err = docker.RestartContainer(contName, 0) + if err != nil { + log.Warnf("Error restarting service container %s. "+ + "Continuing without DNS provider. Error: %v", + contName, err) + return nil + } + + // Refetch container info after restart + cinfo, err = docker.InspectContainer(contName) + if err != nil { + log.Warnf("Error fetching container info after restarting %s"+ + "Continuing without DNS provider. Error: %s", contName, err) + return nil + } + } + + log.Debugf("Container info: %+v\n Hostconfig: %+v", cinfo, cinfo.HostConfig) + // Trim default tenant dnetName := docknet.GetDocknetName(tenantName, networkName, "") err = docker.ConnectNetwork(dnetName, contName) if err != nil { - log.Errorf("Could not attach container(%s) to network %s. Error: %s", + log.Warnf("Could not attach container(%s) to network %s. "+ + "Continuing without DNS provider. Error: %s", contName, dnetName, err) - return fmt.Errorf("Could not attach container(%s) to network %s."+ - "Please make sure %s container is up.", - contName, dnetName, contName) - } - - // inspect the container - cinfo, err := docker.InspectContainer(contName) - if err != nil { - log.Errorf("Error inspecting the container %s. Err: %v", contName, err) - return err + return nil } - log.Debugf("Container info: %+v\n Hostconfig: %+v", cinfo, cinfo.HostConfig) - ninfo, err := docker.InspectNetwork(dnetName) if err != nil { log.Errorf("Error getting network info for %s. Err: %v", dnetName, err) @@ -236,7 +269,7 @@ func detachServiceContainer(tenantName, networkName string) error { return errors.New("Unable to connect to docker") } - dnsContName := tenantName + "dns" + dnsContName := getDNSName(tenantName) cinfo, err := docker.InspectContainer(dnsContName) if err != nil { log.Errorf("Error inspecting the container %s. Err: %v", dnsContName, err) @@ -343,13 +376,15 @@ func DeleteNetworkID(stateDriver core.StateDriver, netID string) error { return core.Errorf("Error: Network has active endpoints") } - if GetClusterMode() == "docker" { + if IsDNSEnabled() { // detach Dns container err = detachServiceContainer(nwCfg.Tenant, nwCfg.NetworkName) if err != nil { log.Errorf("Error detaching service container. Err: %v", err) } + } + if GetClusterMode() == "docker" { // Delete the docker network err = docknet.DeleteDockNet(nwCfg.Tenant, nwCfg.NetworkName, "") if err != nil { @@ -499,9 +534,7 @@ func networkReleaseAddress(nwCfg *mastercfg.CfgNetworkState, ipAddress string) e } func hasActiveEndpoints(nwCfg *mastercfg.CfgNetworkState) bool { - // Uncomment the below after https://github.com/contiv/netplugin/pull/269 is merged // We spin a dns container if IsDNSEnabled() == true // We need to exlude that from Active EPs check. - //return (IsDNSEnabled() && nwCfg.EpCount > 1) || ((!IsDNSEnabled()) && nwCfg.EpCount > 0) - return nwCfg.EpCount > 1 + return (IsDNSEnabled() && nwCfg.EpCount > 1) || ((!IsDNSEnabled()) && nwCfg.EpCount > 0) }