Skip to content

Commit

Permalink
Add Memcached service configuration file and documentation. (#927)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffsheltren authored and andrewfrench committed Aug 2, 2018
1 parent 165ba99 commit 6da3770
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 47 deletions.
14 changes: 12 additions & 2 deletions docs/users/extend/additional-services.md
Expand Up @@ -8,14 +8,24 @@ If you need a service not provided here, see [Defining an additional service wit
This recipe adds an Apache Solr 5.4 container to a project. It will setup a solr core with the solr configuration you define.

**Installation:**

- Copy [docker-compose.solr.yaml](https://github.com/drud/ddev/tree/master/pkg/servicetest/testdata/services/docker-compose.solr.yaml) to the .ddev folder for your project.
- Create the folder path .ddev/solr/conf.
- Copy the solr configuration files for your project to .ddev/solr/conf. _e.g., using Drupal Search API Solr, you would copy the solr-conf/5.x/ contents from the module code base into .ddev/solr/conf._
- Ensure the configuration files must be present before running `ddev start`.

**Interacting with Apache Solr**

- The Solr admin interface will be accessible at `http://<projectname>.ddev.local:8983/solr/`
- To access the Solr container from the web container use `http://solr:8983/solr/`
- The Solr core will be "dev"

## Memcached
This recipe adds a Memcached 1.5 container to a project. The default configuration allocates 128 MB of RAM for the Memcached instance; to change that or other command line arguments, edit the `command` array within the docker-compose file.

**Installation:**
- Copy [docker-compose.memcached.yaml](https://github.com/drud/ddev/tree/master/pkg/servicetest/testdata/services/docker-compose.memcached.yaml) to the .ddev folder for your project.
- Run `ddev start`.

**Interacting with Memcached**
- The Memcached instance will listen on TCP port 11211 (the Memcached default).
- Configure your application to access Memcached on the host:port `memcached:11211`.
- To reach the Memcached admin interface, run `ddev ssh` to connect to the web container, then use `nc` or `telnet` to connect to the Memcached container on port 11211, i.e. `nc memcached 11211`. You can then run commands such as `stats` to see usage information.
112 changes: 69 additions & 43 deletions pkg/servicetest/servicetest_test.go
Expand Up @@ -7,6 +7,8 @@ import (

"path/filepath"

"fmt"

"github.com/drud/ddev/pkg/ddevapp"
"github.com/drud/ddev/pkg/dockerutil"
"github.com/drud/ddev/pkg/fileutil"
Expand Down Expand Up @@ -62,7 +64,8 @@ func TestMain(m *testing.M) {

// TestServices tests each service compose file in the services folder.
// It tests that a site can fully start w/ the compose file present, and
// checks that any exposed HTTP ports return 200.
// runs each service's check function to ensure it's accessible from
// the web container.
func TestServices(t *testing.T) {
assert := asrt.New(t)

Expand All @@ -87,52 +90,75 @@ func TestServices(t *testing.T) {
err = app.Start()
assert.NoError(err)

for _, service := range ServiceFiles {
t.Log("Checking containers for ", service)
serviceName := strings.TrimPrefix(service, "docker-compose.")
serviceName = strings.TrimSuffix(serviceName, ".yaml")

labels := map[string]string{
"com.ddev.site-name": app.GetName(),
"com.docker.compose.service": serviceName,
}

container, findErr := dockerutil.FindContainerByLabels(labels)
assert.NoError(err)
if findErr != nil {
t.Fatalf("Could not find running container for service %s. Skipping remainder of test: %v", serviceName, findErr)
}
name := dockerutil.ContainerName(container)
check, runcheckErr := testcommon.ContainerCheck(name, "running")
assert.NoError(runcheckErr)
assert.True(check, serviceName, "container is running")

// check container env for HTTP_EXPOSE ports to check
expose := dockerutil.GetContainerEnv("HTTP_EXPOSE", container)
if expose != "" {
if strings.Contains(expose, ":") {
ports := strings.Split(expose, ":")
expose = ports[1]
}

containerPorts := container.Ports
for _, port := range containerPorts {
if string(port.PrivatePort) == expose && port.PublicPort != 0 {
log.Debugln("Checking for 200 status for port ", port.PrivatePort)
o := util.NewHTTPOptions("http://127.0.0.1:" + string(port.PublicPort))
o.ExpectedStatus = 200
o.Timeout = 30
runcheckErr = util.EnsureHTTPStatus(o)
assert.NoError(runcheckErr)
}
}
}

}
checkSolrService(t, app)
checkMemcachedService(t, app)

err = app.Down(true)
assert.NoError(err)
site.Cleanup()
}
}
}

// checkSolrService ensures that the solr service's container is
// running and that the service is accessible from the web container
func checkSolrService(t *testing.T, app *ddevapp.DdevApp) {
service := "solr"
port := "8983"
path := fmt.Sprintf("http://%s:%s/solr/", service, port)

var err error
assert := asrt.New(t)
labels := map[string]string{
"com.ddev.site-name": app.GetName(),
"com.docker.compose.service": service,
}

container, err := dockerutil.FindContainerByLabels(labels)
if err != nil {
t.Fatalf("Could not find running container for %s service. Skipping remainder of test: %v", service, err)
}

// Ensure container is running
check, err := testcommon.ContainerCheck(dockerutil.ContainerName(container), "running")
assert.NoError(err)
assert.True(check, "%s container is not running", service)

// Ensure service is accessible from web container
checkCommand := fmt.Sprintf("curl -sL -w '%%{http_code}' '%s' -o /dev/null", path)
out, _, err := app.Exec("web", "sh", "-c", checkCommand)
assert.NoError(err, "Unable to make request to http://%s:%s/solr/", service, port)
assert.Equal("200", out)
}

// checkMemcachedService ensures that the memcached service's
// container is running and that the service is accessible from
// the web container
func checkMemcachedService(t *testing.T, app *ddevapp.DdevApp) {
service := "memcached"
port := "11211"

var err error
assert := asrt.New(t)
labels := map[string]string{
"com.ddev.site-name": app.GetName(),
"com.docker.compose.service": service,
}

container, err := dockerutil.FindContainerByLabels(labels)
if err != nil {
t.Fatalf("Could not find running container for %s service. Skipping remainder of test: %v", service, err)
}

// Ensure container is running
check, err := testcommon.ContainerCheck(dockerutil.ContainerName(container), "running")
assert.NoError(err)
assert.True(check, "%s container is not running", service)

// Ensure service is accessible from web container
checkCommand := fmt.Sprintf("echo stats | nc -t 1 %s %s", service, port)

// We have to ignore the error value, as the '-t 1' timeout option causes a non-zero return value
out, _, _ := app.Exec("web", "sh", "-c", checkCommand)
assert.Contains(out, "STAT pid 1")
}
2 changes: 1 addition & 1 deletion pkg/servicetest/testdata/services/README.md
@@ -1,3 +1,3 @@
# Additional Service Configurations for ddev

This directory contains additional service configurations that can be added to the .ddev directory for a project to enable additional services for the project. Setup instructions for these service files can be found in the [Additional Services Documentation]().
This directory contains additional service configurations that can be added to the .ddev directory for a project to enable additional services for the project. Setup instructions for these service files can be found in the [Additional Services Documentation](https://ddev.readthedocs.io/en/latest/users/extend/additional-services/).
20 changes: 20 additions & 0 deletions pkg/servicetest/testdata/services/docker-compose.memcached.yaml
@@ -0,0 +1,20 @@
# ddev memcached recipe file
#
# To use this in your own project: Copy this file to your project's .ddev folder.
# Edit the 'command' settings to change CLI flags sent to memcached.
# Defaults to '-m 128' to allocate 128 MB of memcached storage.

version: '3'

services:
memcached: # This is the service name used when running ddev commands accepting the --service flag
container_name: ddev-${DDEV_SITENAME}-memcached # This is the name of the container. It is recommended to follow the same name convention used in the main docker-compose.yml file.
image: memcached:1.5
restart: always
ports:
- 11211 # memcached is available at this port inside the container
labels:
# These labels ensure this service is discoverable by ddev
com.ddev.site-name: ${DDEV_SITENAME}

command: ["-m", "128"]
2 changes: 1 addition & 1 deletion pkg/util/network.go
Expand Up @@ -133,7 +133,7 @@ func EnsureHTTPStatus(o *HTTPOptions) error {
}).Info("HTTP Status could not be matched, expected %d, received %d", o.ExpectedStatus, resp.StatusCode)

}
return fmt.Errorf("Failed to match status code %d", o.ExpectedStatus)
return fmt.Errorf("failed to match status code: %d, got: %d", o.ExpectedStatus, resp.StatusCode)
}

// IsPortActive checks to see if the given port on docker IP is answering.
Expand Down

0 comments on commit 6da3770

Please sign in to comment.