@@ -291,6 +291,146 @@ func (c *Controller) DeployS3MockNode(ctx context.Context, clusterID string, exp
291291 return node , nil
292292}
293293
294+ func (c * Controller ) DeployNginxNode (ctx context.Context , clusterID string , expiry time.Duration ) (* NodeInfo , error ) {
295+ nodeID := "nginx"
296+ logger := c .Logger .With (zap .String ("nodeId" , nodeID ))
297+
298+ logger .Debug ("deploying nginx node" )
299+
300+ containerName := "cbdynnode-nginx-" + clusterID
301+
302+ createResult , err := c .DockerCli .ContainerCreate (context .Background (), & container.Config {
303+ Image : "nginx" ,
304+ Labels : map [string ]string {
305+ "com.couchbase.dyncluster.cluster_id" : clusterID ,
306+ "com.couchbase.dyncluster.type" : "nginx" ,
307+ "com.couchbase.dyncluster.purpose" : "nginx backing for cluster" ,
308+ "com.couchbase.dyncluster.node_id" : nodeID ,
309+ },
310+ // same effect as ntp
311+ Volumes : map [string ]struct {}{"/etc/localtime:/etc/localtime" : {}},
312+ }, & container.HostConfig {
313+ AutoRemove : true ,
314+ NetworkMode : container .NetworkMode (c .NetworkName ),
315+ CapAdd : []string {"NET_ADMIN" },
316+ Resources : container.Resources {
317+ Ulimits : []* units.Ulimit {
318+ {Name : "nofile" , Soft : 200000 , Hard : 200000 },
319+ },
320+ },
321+ }, nil , nil , containerName )
322+ if err != nil {
323+ return nil , errors .Wrap (err , "failed to create container" )
324+ }
325+
326+ containerID := createResult .ID
327+
328+ logger .Debug ("container created, starting" , zap .String ("container" , containerID ))
329+
330+ err = c .DockerCli .ContainerStart (context .Background (), containerID , container.StartOptions {})
331+ if err != nil {
332+ return nil , errors .Wrap (err , "failed to start container" )
333+ }
334+
335+ expiryTime := time.Time {}
336+ if expiry > 0 {
337+ expiryTime = time .Now ().Add (expiry )
338+ }
339+
340+ err = c .WriteNodeState (ctx , containerID , & DockerNodeState {
341+ Expiry : expiryTime ,
342+ })
343+ if err != nil {
344+ return nil , errors .Wrap (err , "failed write node state" )
345+ }
346+
347+ // Cheap hack for simpler parsing...
348+ allNodes , err := c .ListNodes (ctx )
349+ if err != nil {
350+ return nil , errors .Wrap (err , "failed to list nodes" )
351+ }
352+
353+ var node * NodeInfo
354+ for _ , allNode := range allNodes {
355+ if allNode .ContainerID == containerID {
356+ node = allNode
357+ }
358+ }
359+ if node == nil {
360+ return nil , errors .New ("failed to find newly created container" )
361+ }
362+
363+ logger .Debug ("container has started, waiting for it to get ready" , zap .String ("address" , node .IPAddress ))
364+
365+ for {
366+ resp , err := http .Get (fmt .Sprintf ("http://%s:%d" , node .IPAddress , 80 ))
367+ if err != nil || resp .StatusCode != 200 {
368+ logger .Debug ("nginx not ready yet" , zap .Error (err ))
369+ time .Sleep (100 * time .Millisecond )
370+ continue
371+ }
372+
373+ break
374+ }
375+
376+ logger .Debug ("container is ready!" )
377+
378+ return node , nil
379+ }
380+
381+ func (c * Controller ) UpdateNginxConfig (ctx context.Context , containerID string , addrs []string ) error {
382+ c .Logger .Debug ("writing nginx config" , zap .String ("container" , containerID ), zap .Any ("addrs" , addrs ))
383+
384+ var nginxConf string
385+ writeForwardedPort := func (port string ) {
386+ if len (addrs ) > 0 {
387+ nginxConf += "upstream backend" + port + " {\n "
388+ for _ , addr := range addrs {
389+ nginxConf += " server " + addr + ":" + port + ";\n "
390+ }
391+ nginxConf += "}\n "
392+ nginxConf += "server {\n "
393+ nginxConf += " listen " + port + ";\n "
394+ nginxConf += " location / {\n "
395+ nginxConf += " proxy_pass http://backend" + port + ";\n "
396+ nginxConf += " proxy_set_header Host $http_host;\n "
397+ nginxConf += " proxy_set_header X-Real-IP $remote_addr;\n "
398+ nginxConf += " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n "
399+ nginxConf += " }\n "
400+ nginxConf += "}\n "
401+ }
402+ }
403+ writeForwardedPort ("8091" )
404+ writeForwardedPort ("8092" )
405+ writeForwardedPort ("8093" )
406+ writeForwardedPort ("8094" )
407+ writeForwardedPort ("8095" )
408+ writeForwardedPort ("8096" )
409+
410+ confBytes := []byte (nginxConf )
411+
412+ tarBuf := bytes .NewBuffer (nil )
413+ tarFile := tar .NewWriter (tarBuf )
414+ tarFile .WriteHeader (& tar.Header {
415+ Name : "cb.conf" ,
416+ Size : int64 (len (confBytes )),
417+ })
418+ tarFile .Write (confBytes )
419+ tarFile .Flush ()
420+
421+ err := c .DockerCli .CopyToContainer (ctx , containerID , "/etc/nginx/conf.d/" , tarBuf , container.CopyToContainerOptions {})
422+ if err != nil {
423+ return errors .Wrap (err , "failed to write nginx config" )
424+ }
425+
426+ err = c .execCmd (ctx , containerID , []string {"nginx" , "-s" , "reload" })
427+ if err != nil {
428+ return errors .Wrap (err , "failed to reload nginx config" )
429+ }
430+
431+ return nil
432+ }
433+
294434type DeployNodeOptions struct {
295435 Purpose string
296436 Expiry time.Duration
0 commit comments