Add support for creating network if it is missing

This commit is contained in:
Dane Everitt 2019-12-07 17:31:12 -08:00
parent 21d8384848
commit 91d5735ba8
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
3 changed files with 149 additions and 24 deletions

View File

@ -108,29 +108,48 @@ type SftpConfiguration struct {
ReadOnly bool `default:"false" yaml:"read_only"` ReadOnly bool `default:"false" yaml:"read_only"`
} }
type dockerNetworkInterfaces struct {
V4 struct {
Subnet string `default:"172.18.0.0/16"`
Gateway string `default:"172.18.0.1"`
}
V6 struct {
Subnet string `default:"fdba:17c8:6c94::/64"`
Gateway string `default:"fdba:17c8:6c94::1011"`
}
}
type DockerNetworkConfiguration struct {
// The interface that should be used to create the network. Must not conflict
// with any other interfaces in use by Docker or on the system.
Interface string `default:"172.18.0.1"`
// The name of the network to use. If this network already exists it will not
// be created. If it is not found, a new network will be created using the interface
// defined.
Name string `default:"pterodactyl_nw"`
ISPN bool `default:"false" yaml:"ispn"`
Driver string `default:"bridge"`
IsInternal bool `default:"false" yaml:"is_internal"`
EnableICC bool `default:"true" yaml:"enable_icc"`
Interfaces *dockerNetworkInterfaces `yaml:"interfaces"`
}
// Defines the docker configuration used by the daemon when interacting with // Defines the docker configuration used by the daemon when interacting with
// containers and networks on the system. // containers and networks on the system.
type DockerConfiguration struct { type DockerConfiguration struct {
// Network configuration that should be used when creating a new network // Network configuration that should be used when creating a new network
// for containers run through the daemon. // for containers run through the daemon.
Network struct { Network *DockerNetworkConfiguration `yaml:"network"`
// The interface that should be used to create the network. Must not conflict
// with any other interfaces in use by Docker or on the system.
Interface string
// The name of the network to use. If this network already exists it will not
// be created. If it is not found, a new network will be created using the interface
// defined.
Name string
}
// If true, container images will be updated when a server starts if there // If true, container images will be updated when a server starts if there
// is an update available. If false the daemon will not attempt updates and will // is an update available. If false the daemon will not attempt updates and will
// defer to the host system to manage image updates. // defer to the host system to manage image updates.
UpdateImages bool `yaml:"update_images"` UpdateImages bool `default:"true" yaml:"update_images"`
// The location of the Docker socket. // The location of the Docker socket.
Socket string Socket string `default:"/var/run/docker.sock"`
// Defines the location of the timezone file on the host system that should // Defines the location of the timezone file on the host system that should
// be mounted into the created containers so that they all use the same time. // be mounted into the created containers so that they all use the same time.
@ -167,8 +186,11 @@ func (c *Configuration) SetDefaults() {
Username: "pterodactyl", Username: "pterodactyl",
Data: "/srv/daemon-data", Data: "/srv/daemon-data",
TimezonePath: "/etc/timezone", TimezonePath: "/etc/timezone",
Sftp: &SftpConfiguration{},
} }
defaults.SetDefaults(c.System.Sftp)
// By default the internal webserver should bind to all interfaces and // By default the internal webserver should bind to all interfaces and
// be served on port 8080. // be served on port 8080.
c.Api = &ApiConfiguration{ c.Api = &ApiConfiguration{
@ -195,11 +217,14 @@ func (c *Configuration) SetDefaults() {
c.Throttles.CheckInterval = 100 c.Throttles.CheckInterval = 100
// Configure the defaults for Docker connection and networks. // Configure the defaults for Docker connection and networks.
c.Docker = &DockerConfiguration{} c.Docker = &DockerConfiguration{
c.Docker.UpdateImages = true Network: &DockerNetworkConfiguration{
c.Docker.Socket = "/var/run/docker.sock" Interfaces: &dockerNetworkInterfaces{},
c.Docker.Network.Name = "pterodactyl_nw" },
c.Docker.Network.Interface = "172.18.0.1" }
defaults.SetDefaults(c.Docker)
defaults.SetDefaults(c.Docker.Network)
defaults.SetDefaults(c.Docker.Network.Interfaces)
} }
// Reads the configuration from the provided file and returns the configuration // Reads the configuration from the provided file and returns the configuration
@ -210,13 +235,8 @@ func ReadConfiguration(path string) (*Configuration, error) {
return nil, err return nil, err
} }
sftp :=new(SftpConfiguration)
defaults.SetDefaults(sftp)
c := new(Configuration) c := new(Configuration)
c.System = new(SystemConfiguration) c.SetDefaults()
c.System.Sftp = sftp
defaults.SetDefaults(c)
// Replace environment variables within the configuration file with their // Replace environment variables within the configuration file with their
// values from the host system. // values from the host system.

95
environment.go Normal file
View File

@ -0,0 +1,95 @@
package main
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/pterodactyl/wings/config"
"go.uber.org/zap"
)
// Configures the required network for the docker environment.
func ConfigureDockerEnvironment(c *config.DockerConfiguration) error {
// Ensure the required docker network exists on the system.
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return err
}
resource, err := cli.NetworkInspect(context.Background(), c.Network.Name, types.NetworkInspectOptions{})
if err != nil && client.IsErrNotFound(err) {
zap.S().Infow("creating missing pterodactyl0 interface, this could take a few seconds...")
return createDockerNetwork(cli, c)
} else if err != nil {
zap.S().Fatalw("failed to create required docker network for containers", zap.Error(err))
}
switch resource.Driver {
case "host":
c.Network.Interface = "127.0.0.1"
c.Network.ISPN = false
return nil
case "overlay":
case "weavemesh":
c.Network.Interface = ""
c.Network.ISPN = true
return nil
default:
c.Network.ISPN = false
}
return nil
}
// Creates a new network on the machine if one does not exist already.
func createDockerNetwork(cli *client.Client, c *config.DockerConfiguration) error {
_, err := cli.NetworkCreate(context.Background(), c.Network.Name, types.NetworkCreate{
Driver: c.Network.Driver,
EnableIPv6: true,
Internal: c.Network.IsInternal,
IPAM: &network.IPAM{
Config: []network.IPAMConfig{
{
Subnet: c.Network.Interfaces.V4.Subnet,
Gateway: c.Network.Interfaces.V4.Gateway,
},
{
Subnet: c.Network.Interfaces.V6.Subnet,
Gateway: c.Network.Interfaces.V6.Gateway,
},
},
},
Options: map[string]string{
"encryption": "false",
"com.docker.network.bridge.default_bridge": "false",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "pterodactyl0",
"com.docker.network.driver.mtu": "1500",
},
})
if err != nil {
return err
}
switch c.Network.Driver {
case "host":
c.Network.Interface = "127.0.0.1"
c.Network.ISPN = false
break
case "overlay":
case "weavemesh":
c.Network.Interface = ""
c.Network.ISPN = true
break
default:
c.Network.Interface = c.Network.Interfaces.V4.Gateway
c.Network.ISPN = false
break
}
return nil
}

View File

@ -12,6 +12,7 @@ import (
"github.com/remeh/sizedwaitgroup" "github.com/remeh/sizedwaitgroup"
"go.uber.org/zap" "go.uber.org/zap"
"net/http" "net/http"
"os"
) )
// Entrypoint for the Wings application. Configures the logger and checks any // Entrypoint for the Wings application. Configures the logger and checks any
@ -70,6 +71,15 @@ func main() {
return return
} }
if err := ConfigureDockerEnvironment(c.Docker); err != nil {
zap.S().Fatalw("failed to configure docker environment", zap.Error(errors.WithStack(err)))
os.Exit(1)
}
if err := c.WriteToDisk(); err != nil {
zap.S().Errorw("failed to save configuration to disk", zap.Error(errors.WithStack(err)))
}
// Just for some nice log output. // Just for some nice log output.
for _, s := range server.GetServers().All() { for _, s := range server.GetServers().All() {
zap.S().Infow("loaded configuration for server", zap.String("server", s.Uuid)) zap.S().Infow("loaded configuration for server", zap.String("server", s.Uuid))
@ -143,7 +153,7 @@ func main() {
} }
r := &Router{ r := &Router{
token: c.AuthenticationToken, token: c.AuthenticationToken,
upgrader: websocket.Upgrader{ upgrader: websocket.Upgrader{
// Ensure that the websocket request is originating from the Panel itself, // Ensure that the websocket request is originating from the Panel itself,
// and not some other location. // and not some other location.