github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/old/main.go (about)

     1  package old
     2  
     3  import (
     4  	"bytes"
     5  	"flag"
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"os/exec"
    10  	"os/signal"
    11  	"runtime"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/cloudfoundry/gunk/command_runner"
    16  	"github.com/cloudfoundry/gunk/localip"
    17  	"github.com/docker/docker/daemon/graphdriver"
    18  	_ "github.com/docker/docker/daemon/graphdriver/aufs"
    19  	_ "github.com/docker/docker/daemon/graphdriver/vfs"
    20  	"github.com/docker/docker/graph"
    21  	"github.com/docker/docker/registry"
    22  	"github.com/pivotal-golang/clock"
    23  	"github.com/pivotal-golang/lager"
    24  
    25  	"github.com/cloudfoundry-incubator/cf-debug-server"
    26  	"github.com/cloudfoundry-incubator/cf-lager"
    27  	"github.com/cloudfoundry-incubator/garden-linux/container_pool"
    28  	"github.com/cloudfoundry-incubator/garden-linux/container_repository"
    29  	"github.com/cloudfoundry-incubator/garden-linux/linux_backend"
    30  	"github.com/cloudfoundry-incubator/garden-linux/network"
    31  	"github.com/cloudfoundry-incubator/garden-linux/network/bridgemgr"
    32  	"github.com/cloudfoundry-incubator/garden-linux/network/devices"
    33  	"github.com/cloudfoundry-incubator/garden-linux/network/iptables"
    34  	"github.com/cloudfoundry-incubator/garden-linux/network/subnets"
    35  	"github.com/cloudfoundry-incubator/garden-linux/old/port_pool"
    36  	"github.com/cloudfoundry-incubator/garden-linux/old/quota_manager"
    37  	"github.com/cloudfoundry-incubator/garden-linux/old/repository_fetcher"
    38  	"github.com/cloudfoundry-incubator/garden-linux/old/rootfs_provider"
    39  	"github.com/cloudfoundry-incubator/garden-linux/old/sysconfig"
    40  	"github.com/cloudfoundry-incubator/garden-linux/old/system_info"
    41  	"github.com/cloudfoundry-incubator/garden/server"
    42  	"github.com/cloudfoundry/dropsonde"
    43  	"github.com/cloudfoundry/gunk/command_runner/linux_command_runner"
    44  )
    45  
    46  const (
    47  	DefaultNetworkPool = "10.254.0.0/22"
    48  	DefaultMTUSize     = 1500
    49  )
    50  
    51  var listenNetwork = flag.String(
    52  	"listenNetwork",
    53  	"unix",
    54  	"how to listen on the address (unix, tcp, etc.)",
    55  )
    56  
    57  var listenAddr = flag.String(
    58  	"listenAddr",
    59  	"/tmp/garden.sock",
    60  	"address to listen on",
    61  )
    62  
    63  var snapshotsPath = flag.String(
    64  	"snapshots",
    65  	"",
    66  	"directory in which to store container state to persist through restarts",
    67  )
    68  
    69  var binPath = flag.String(
    70  	"bin",
    71  	"",
    72  	"directory containing backend-specific scripts (i.e. ./create.sh)",
    73  )
    74  
    75  var depotPath = flag.String(
    76  	"depot",
    77  	"",
    78  	"directory in which to store containers",
    79  )
    80  
    81  var overlaysPath = flag.String(
    82  	"overlays",
    83  	"",
    84  	"directory in which to store containers mount points",
    85  )
    86  
    87  var rootFSPath = flag.String(
    88  	"rootfs",
    89  	"",
    90  	"directory of the rootfs for the containers",
    91  )
    92  
    93  var disableQuotas = flag.Bool(
    94  	"disableQuotas",
    95  	false,
    96  	"disable disk quotas",
    97  )
    98  
    99  var containerGraceTime = flag.Duration(
   100  	"containerGraceTime",
   101  	0,
   102  	"time after which to destroy idle containers",
   103  )
   104  
   105  var portPoolStart = flag.Uint(
   106  	"portPoolStart",
   107  	61001,
   108  	"start of ephemeral port range used for mapped container ports",
   109  )
   110  
   111  var portPoolSize = flag.Uint(
   112  	"portPoolSize",
   113  	5000,
   114  	"size of port pool used for mapped container ports",
   115  )
   116  
   117  var uidMappingOffset = flag.Int(
   118  	"uidMappingOffset",
   119  	600000,
   120  	"start of mapped UID range for unprivileged containers (the root user in an unprivileged container will have this host uid)",
   121  )
   122  
   123  var networkPool = flag.String("networkPool",
   124  	DefaultNetworkPool,
   125  	"Pool of dynamically allocated container subnets")
   126  
   127  var denyNetworks = flag.String(
   128  	"denyNetworks",
   129  	"",
   130  	"CIDR blocks representing IPs to blacklist",
   131  )
   132  
   133  var allowNetworks = flag.String(
   134  	"allowNetworks",
   135  	"",
   136  	"CIDR blocks representing IPs to whitelist",
   137  )
   138  
   139  var graphRoot = flag.String(
   140  	"graph",
   141  	"/var/lib/garden-docker-graph",
   142  	"docker image graph",
   143  )
   144  
   145  var dockerRegistry = flag.String(
   146  	"registry",
   147  	registry.IndexServerAddress(),
   148  	"docker registry API endpoint",
   149  )
   150  
   151  var insecureRegistries = flag.String(
   152  	"insecureDockerRegistryList",
   153  	"",
   154  	"comma-separated list of docker registries to allow connection to even if they are not secure",
   155  )
   156  
   157  var tag = flag.String(
   158  	"tag",
   159  	"",
   160  	"server-wide identifier used for 'global' configuration, must be less than 3 character long",
   161  )
   162  
   163  var dropsondeOrigin = flag.String(
   164  	"dropsondeOrigin",
   165  	"garden-linux",
   166  	"Origin identifier for dropsonde-emitted metrics.",
   167  )
   168  
   169  var dropsondeDestination = flag.String(
   170  	"dropsondeDestination",
   171  	"localhost:3457",
   172  	"Destination for dropsonde-emitted metrics.",
   173  )
   174  
   175  var allowHostAccess = flag.Bool(
   176  	"allowHostAccess",
   177  	false,
   178  	"allow network access to host",
   179  )
   180  
   181  var iptablesLogMethod = flag.String(
   182  	"iptablesLogMethod",
   183  	"kernel",
   184  	"type of iptable logging to use, one of 'kernel' or 'nflog' (default: kernel)",
   185  )
   186  
   187  var mtu = flag.Int(
   188  	"mtu",
   189  	DefaultMTUSize,
   190  	"MTU size for container network interfaces")
   191  
   192  var externalIP = flag.String(
   193  	"externalIP",
   194  	"",
   195  	"IP address to use to reach container's mapped ports")
   196  
   197  func Main() {
   198  
   199  	cf_debug_server.AddFlags(flag.CommandLine)
   200  	cf_lager.AddFlags(flag.CommandLine)
   201  	flag.Parse()
   202  
   203  	runtime.GOMAXPROCS(runtime.NumCPU())
   204  
   205  	logger, reconfigurableSink := cf_lager.New("garden-linux")
   206  	if dbgAddr := cf_debug_server.DebugAddress(flag.CommandLine); dbgAddr != "" {
   207  		cf_debug_server.Run(dbgAddr, reconfigurableSink)
   208  	}
   209  
   210  	initializeDropsonde(logger)
   211  
   212  	if *binPath == "" {
   213  		missing("-bin")
   214  	}
   215  
   216  	if *depotPath == "" {
   217  		missing("-depot")
   218  	}
   219  
   220  	if *overlaysPath == "" {
   221  		missing("-overlays")
   222  	}
   223  
   224  	if len(*tag) > 2 {
   225  		println("-tag parameter must be less than 3 characters long")
   226  		println()
   227  		flag.Usage()
   228  		return
   229  	}
   230  
   231  	_, dynamicRange, _ := net.ParseCIDR(*networkPool)
   232  	subnetPool, _ := subnets.NewSubnets(dynamicRange)
   233  
   234  	// TODO: use /proc/sys/net/ipv4/ip_local_port_range by default (end + 1)
   235  	portPool := port_pool.New(uint32(*portPoolStart), uint32(*portPoolSize))
   236  
   237  	useKernelLogging := true
   238  	switch *iptablesLogMethod {
   239  	case "nflog":
   240  		useKernelLogging = false
   241  	case "kernel":
   242  		/* noop */
   243  	default:
   244  		println("-iptablesLogMethod value not recognized")
   245  		println()
   246  		flag.Usage()
   247  		return
   248  	}
   249  
   250  	config := sysconfig.NewConfig(*tag, *allowHostAccess)
   251  
   252  	runner := sysconfig.NewRunner(config, linux_command_runner.New())
   253  
   254  	quotaManager := quota_manager.New(runner, getMountPoint(logger, *depotPath), *binPath)
   255  
   256  	if *disableQuotas {
   257  		quotaManager.Disable()
   258  	}
   259  
   260  	if err := os.MkdirAll(*graphRoot, 0755); err != nil {
   261  		logger.Fatal("failed-to-create-graph-directory", err)
   262  	}
   263  
   264  	graphDriver, err := graphdriver.New(*graphRoot, nil)
   265  	if err != nil {
   266  		logger.Fatal("failed-to-construct-graph-driver", err)
   267  	}
   268  
   269  	graph, err := graph.NewGraph(*graphRoot, graphDriver)
   270  	if err != nil {
   271  		logger.Fatal("failed-to-construct-graph", err)
   272  	}
   273  
   274  	repoFetcher := repository_fetcher.Retryable{
   275  		repository_fetcher.New(
   276  			repository_fetcher.NewRepositoryProvider(
   277  				*dockerRegistry,
   278  				strings.Split(*insecureRegistries, ","),
   279  			),
   280  			graph,
   281  		),
   282  	}
   283  
   284  	uidMappings := rootfs_provider.MappingList{{
   285  		FromID: 0,
   286  		ToID:   *uidMappingOffset,
   287  		Size:   65534, // map an almost-16-bit range
   288  	}}
   289  
   290  	rootFSNamespacer := &rootfs_provider.UidNamespacer{
   291  		Logger: logger,
   292  		Translator: rootfs_provider.NewUidTranslator(
   293  			uidMappings,
   294  			uidMappings,
   295  		).Translate,
   296  	}
   297  
   298  	copier := &rootfs_provider.ShellOutCp{}
   299  	dockerRootFSProvider, err := rootfs_provider.NewDocker(repoFetcher, graphDriver, rootfs_provider.SimpleVolumeCreator{}, rootFSNamespacer, copier, clock.NewClock())
   300  	if err != nil {
   301  		logger.Fatal("failed-to-construct-docker-rootfs-provider", err)
   302  	}
   303  
   304  	rootFSProviders := map[string]rootfs_provider.RootFSProvider{
   305  		"":       rootfs_provider.NewOverlay(*binPath, *overlaysPath, *rootFSPath, runner),
   306  		"docker": dockerRootFSProvider,
   307  	}
   308  
   309  	filterProvider := &provider{
   310  		useKernelLogging: useKernelLogging,
   311  		chainPrefix:      config.IPTables.Filter.InstancePrefix,
   312  		runner:           runner,
   313  		log:              logger,
   314  	}
   315  
   316  	if *externalIP == "" {
   317  		ip, err := localip.LocalIP()
   318  		if err != nil {
   319  			panic("couldn't determine local IP to use for -externalIP parameter. You can use the -externalIP flag to pass an external IP")
   320  		}
   321  
   322  		externalIP = &ip
   323  	}
   324  
   325  	parsedExternalIP := net.ParseIP(*externalIP)
   326  	if parsedExternalIP == nil {
   327  		panic(fmt.Sprintf("Value of -externalIP %s could not be converted to an IP", *externalIP))
   328  	}
   329  
   330  	pool := container_pool.New(
   331  		logger,
   332  		*binPath,
   333  		*depotPath,
   334  		config,
   335  		rootFSProviders,
   336  		*uidMappingOffset,
   337  		parsedExternalIP,
   338  		*mtu,
   339  		subnetPool,
   340  		bridgemgr.New("w"+config.Tag+"b-", &devices.Bridge{}, &devices.Link{}),
   341  		filterProvider,
   342  		iptables.NewGlobalChain(config.IPTables.Filter.DefaultChain, runner, logger.Session("global-chain")),
   343  		portPool,
   344  		strings.Split(*denyNetworks, ","),
   345  		strings.Split(*allowNetworks, ","),
   346  		runner,
   347  		quotaManager,
   348  	)
   349  
   350  	systemInfo := system_info.NewProvider(*depotPath)
   351  
   352  	backend := linux_backend.New(logger, pool, container_repository.New(), systemInfo, *snapshotsPath)
   353  
   354  	err = backend.Setup()
   355  	if err != nil {
   356  		logger.Fatal("failed-to-set-up-backend", err)
   357  	}
   358  
   359  	graceTime := *containerGraceTime
   360  
   361  	gardenServer := server.New(*listenNetwork, *listenAddr, graceTime, backend, logger)
   362  
   363  	err = gardenServer.Start()
   364  	if err != nil {
   365  		logger.Fatal("failed-to-start-server", err)
   366  	}
   367  
   368  	signals := make(chan os.Signal, 1)
   369  
   370  	go func() {
   371  		<-signals
   372  		gardenServer.Stop()
   373  		os.Exit(0)
   374  	}()
   375  
   376  	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
   377  
   378  	logger.Info("started", lager.Data{
   379  		"network": *listenNetwork,
   380  		"addr":    *listenAddr,
   381  	})
   382  
   383  	select {}
   384  }
   385  
   386  func getMountPoint(logger lager.Logger, depotPath string) string {
   387  	dfOut := new(bytes.Buffer)
   388  
   389  	df := exec.Command("df", depotPath)
   390  	df.Stdout = dfOut
   391  	df.Stderr = os.Stderr
   392  
   393  	err := df.Run()
   394  	if err != nil {
   395  		logger.Fatal("failed-to-get-mount-info", err)
   396  	}
   397  
   398  	dfOutputWords := strings.Split(string(dfOut.Bytes()), " ")
   399  
   400  	return strings.Trim(dfOutputWords[len(dfOutputWords)-1], "\n")
   401  }
   402  
   403  func missing(flagName string) {
   404  	println("missing " + flagName)
   405  	println()
   406  	flag.Usage()
   407  }
   408  
   409  func initializeDropsonde(logger lager.Logger) {
   410  	err := dropsonde.Initialize(*dropsondeDestination, *dropsondeOrigin)
   411  	if err != nil {
   412  		logger.Error("failed to initialize dropsonde: %v", err)
   413  	}
   414  }
   415  
   416  type provider struct {
   417  	useKernelLogging bool
   418  	chainPrefix      string
   419  	runner           command_runner.CommandRunner
   420  	log              lager.Logger
   421  }
   422  
   423  func (p *provider) ProvideFilter(containerId string) network.Filter {
   424  	return network.NewFilter(iptables.NewLoggingChain(p.chainPrefix+containerId, p.useKernelLogging, p.runner, p.log.Session(containerId).Session("filter")))
   425  }