diff --git a/docs/examples/README.md b/docs/examples/README.md index 4017504159..9342f33681 100644 --- a/docs/examples/README.md +++ b/docs/examples/README.md @@ -1,5 +1,6 @@ # Examples -The source code for the examples in this section can be found in our Github [examples repository](https://github.com/garden-io/garden-examples/). +The source code for the examples in this section can be found in our Github repository under the +[examples directory](https://github.com/garden-io/garden/examples/). * [Simple Project](./simple-project.md) \ No newline at end of file diff --git a/docs/examples/simple-project.md b/docs/examples/simple-project.md index 3fb5405b88..0a804a7704 100644 --- a/docs/examples/simple-project.md +++ b/docs/examples/simple-project.md @@ -17,12 +17,12 @@ This tutorial assumes that you have already have a running [installation of Gard ## Clone the example repo -The code for this tutorial can be found on Github in our [examples repo](https://github.com/garden-io/garden-examples). We'll use the [simple-project-start](https://github.com/garden-io/garden-examples/simple-project-start) example and work our way from there. The complete version is under [simple-project](https://github.com/garden-io/garden-examples/simple-project). +The code for this tutorial can be found on Github in our [examples repo](https://github.com/garden-io/garden/examples). We'll use the [simple-project-start](https://github.com/garden-io/garden/examples/simple-project-start) example and work our way from there. The complete version is under [simple-project](https://github.com/garden-io/garden/examples/simple-project). First, let's clone the examples repo, change into the directory, and take a look inside: ```sh -$ git clone https://github.com/garden-io/garden-examples.git -$ cd garden-examples/simple-project-start +$ git clone https://github.com/garden-io/garden/examples.git +$ cd garden/examples/simple-project-start $ tree . . └── services diff --git a/docs/guides/configuration.md b/docs/guides/configuration.md index 1c3f3042e8..4ec85c6152 100644 --- a/docs/guides/configuration.md +++ b/docs/guides/configuration.md @@ -1,75 +1,66 @@ -## Configuration +# Configuration Garden is configured via `garden.yml` configuration files. The [project-wide](#project-configuration) `garden.yml` file should be located in the top-level directory of the -project's Git -repository. +project's Git repository. -In addition, each of the project's [modules](../guides/glossary.md#module)' `garden.yml` should be located in that module's -top-level -directory. - -Currently, Garden projects assume that all their modules are rooted in subdirectories of the same Git repository. -In a future release, this mono-repo structure will be made optional. +In addition, each of the project's [modules](../guides/glossary.md#module)' `garden.yml` should be located in that +module's top-level directory. To get started, create a `garden.yml` file in the top-level directory of your repository, and a `garden.yml` file in the top-level directory of each of the modules you'd like do define for your project. To decide how to split your project up into modules, it's useful to consider what parts of it are built as a single step, and what the dependency relationships are between your build steps. For example, each container and each -serverless function should be represented by its own module - -Then, you can configure each module's endpoints via the [`services` directive](#services) in its `garden.yml`. +serverless function should be represented by its own module. Below, we'll be using examples from the -[hello-world example project](https://github.com/garden-io/garden/tree/528b141717f718ebe304d2ebde87b85d0c6c5e50/examples/hello-world). +[hello-world example project](https://github.com/garden-io/garden/tree/master/examples/hello-world), which touches +on many of the things you're likely to want to configure in a project. + +## Project Configuration + +We'll start by looking at the top-level [project configuration file](https://github.com/garden-io/garden/blob/master/examples/hello-world/garden.yml). -### Project Configuration -[Github link](https://github.com/garden-io/garden/blob/528b141717f718ebe304d2ebde87b85d0c6c5e50/examples/hello-world/garden.yml) ```yaml # examples/hello-world/garden.yml project: name: hello-world - global: - providers: - - name: container - - name: npm-package + environmentDefaults: variables: my-variable: hello-variable environments: - name: local providers: - name: local-kubernetes - - name: local-google-cloud-functions - - name: dev - providers: - - name: google-app-engine - - name: google-cloud-functions - default-project: garden-hello-world + - name: openfaas ``` -The project-wide `garden.yml` defines the project's name, the default providers used for each -[plugin](../guides/glossary.md#plugin) the project requires (via the `global` directive), and -[environment](../guides/glossary.md#environment)-specific provider overrides as is appropriate for each of the project's -configured environments (`local` and `dev` under the `environments` directive above). + +The project-wide `garden.yml` defines the project's name, the default configuration used for each +[environment](../guides/glossary.md#environment) (via the `environmentDefaults` directive), and +environment-specific provider configuration. The above only configures a `local` environment, but you could add +further environments, such as a remote Kubernetes environment. Here, project-wide configuration variables can also be specified (global, and/or environment-specific). These are then available for interpolation in any string scalar value in any module's `garden.yml`. - For example, assuming the above project configuration, `"foo-${variables.my-variable}-bar"` would evaluate to - `"foo-hello-variable-bar"` when used as a scalar string value in a module's `garden.yml`. +For example, assuming the above project configuration, `"foo-${variables.my-variable}-bar"` would evaluate to +`"foo-hello-variable-bar"` when used as a scalar string value in a module's `garden.yml`. + +## Module Configuration -### Module Configuration Below, we'll use the module configurations of `hello-function` and `hello-container` from the -[hello-world example project](https://github.com/garden-io/garden/tree/528b141717f718ebe304d2ebde87b85d0c6c5e50/examples/hello-world) +[hello-world example project](https://github.com/garden-io/garden/tree/master/examples/hello-world) as examples to illustrate some of the primary module-level configuration options. -The following is a snippet from [`hello-function`'s module config](#hello-function-module-configuration): +The following is a snippet from [`hello-container`'s module config](#hello-function-module-configuration): + ```yaml module: - description: Hello world serverless function - type: google-cloud-function - name: hello-function + name: hello-container + type: container + description: Hello world container service ... build: dependencies: @@ -79,26 +70,38 @@ module: target: libraries/hello-npm-package/ ``` -#### name +The first lines you'll find in all module configurations, and describe the module at a high level. + +The second part, the `build` key, demonstrates how Garden can serve as a build framework, managing build dependencies +and even copying files between modules as they are built. + +Below is a run-down of the individual configuration keys, and what they represent: + +### name + The module's name, used e.g. when referring to it from another module's configuration as a [build dependency](#build-configuration), or when building specific modules with `garden build`. Note that module names must be unique within a given project. An error will be thrown in any Garden CLI command if two modules use the same name. -#### type -A [module](../guides/glossary.md#module)'s `type` specifies its plugin type. Garden interprets this according to the -active environment's configured provider for the specified plugin type. +### type + +A [module](../guides/glossary.md#module)'s `type` specifies what kind of module this is, which will control how the +module's code gets built, tested, deployed etc. The module types are defined by _plugins_. The built-in plug-ins +include `container` and `generic` (which basically provides a way to run commands locally). + +The example above is a `container` module, and the `hello-function` module is an `openfaas` module +(which is one of many ways to run functions-as-a-service on Kubernetes). + +In this particular project, the `container` module type is deployed by the `local-kubernetes` plugin, and the +`openfaas` module is built and deployed by the corresponding `openfaas` plugin. -For example, -[`hello-container`](#hello-container-module-configuration)'s `type` is set to `container`, which the -[project configuration](#project-configuration) above interprets as `local-kubernetes` (a Docker container managed -via a local Kubernetes installation), assuming that the `local` environment is being used. +### build -#### build A module's build configuration is specified via the `build` directive. -Under `build`, the `command` subdirective sets the CLI command run during builds. A module's build command is executed +Here, the `build.command` subdirective sets the CLI command run during builds. A module's build command is executed with its working directory set to a copy of the module's top-level directory, located at `[project-root]/.garden/build/[module-name]`. This internal directory is referred to as the module's [build directory](../guides/glossary.md#build-directory). @@ -106,13 +109,27 @@ with its working directory set to a copy of the module's top-level directory, lo The `.garden` directory should not be modified by users, since this may lead to unexpected errors when the Garden CLI tools are used in the project. -##### Build Dependencies -The `dependencies` subdirective lists the module's build dependencies. `name` is the required module's name, and -`copy` indicates what files/folders, if any, should be copied from the required module's build directory to the -module in question after the required module is built (`source`), and where they should be copied (`target). +The `build.dependencies` subdirective lists the module's build dependencies, which need to be built ahead of this module. +`name` is the required module's name. In many cases you only need to declare the build dependency name. For example, +you simply need to build one container before another because it's used as a base image. + +In other cases, you may actually need files to be copied from one built module to another. +The `copy` key indicates what files/folders, if any, should be copied from the required module's build directory to the +module in question after the required module is built (`source`), and where they should be copied (`target`). + +In the above example, we copy the entire contents of `hello-npm-package`'s build directory, after it has been built, +into the `libraries/hello-npm-package/` in the `hello-container` build directory, _before the container is built_. + +## Services + +A module may contain zero or more _services_. Services are deployed when running `garden deploy` or `garden dev` as +part of your runtime stack. + +How services are configured will depend on the module type. An `openfaas` module always contains a single service. A +`container` module can contain any number of services (or none at all, if it's just used as a base image, for example). -#### Services The following is a snippet from [`hello-container's`'s module config](#hello-container-module-configuration): + ```yaml module: description: Hello world container service @@ -134,34 +151,22 @@ module: - hello-function ... ``` -The `services` directive defines the services exposed by the module. - -##### name -The service's name, used e.g. when referring to it as a dependency of another service, or when deploying -specific services with `garden deploy`. Service names must be unique across all modules within a given project. An -error will be thrown in any Garden CLI command if two services use the same name. - -##### command -The CLI command to be executed (after the module is built) to make the service's endpoints available. -##### ports -Names each port exposed by the service. +Here the `services` directive defines the services exposed by the module. We only have one service in this example, +but you might for example add another service, for example a background worker, that is started using a different +`command`. -##### endpoints -Enumerates the functional endpoints exposed by the service, defining the relative path and port to associate with -each of them. +For more details on how to configure services in a `container` module, please refer to the +[config reference](../reference/config.md). -##### healthcheck -Defines the endpoint used to query the service's availability. +## Tests -##### dependencies -Lists the names of the services that must be deployed before the service in question (the `hello-container` service, in -this case) is deployed. +Each module can define one or more test suites. How these tests are specified, much like services, depends on the +individual module type. However the concepts are most often the same; you specify one or more test suites, how to +execute them, and in some cases which services need to be running for the tests to run successfully. -##### tests -A list of named test configurations for the module. +For an example, here is another snippet from the `hello-container` module configuration: -Following is another snippet from [`hello-container`'s module config](#hello-container-module-configuration): ```yaml module: description: Hello world container service @@ -175,70 +180,22 @@ module: dependencies: - hello-function ``` -Test groups can be run by `name` via `garden test`. `command` is the CLI command to run the specified tests, and -`dependencies` lists (by name) the services (if any) that must be deployed before the test group in question is run. -#### Functions (experimental) -For modules defining serverless functions, the `functions` directive specifies the names and entry points of the -functions the module exposes. Note that serverless functionality is still experimental and under active development. +Here we define two types of tests. First are unit tests, which can be run on their own without any dependencies. The +framework only needs to know which command to run, and the rest is handled by the module's code itself. -This section is currently only included to clarify the `functions` directive in -[`hello-function`'s module config](#hello-function-module-configuration), since it's used as an example here. +The other test suite, `integ`, leverages the Garden framework's ability to manage runtime dependencies for tests. In +this case, the integ test suite needs the `hello-function` service to be running for the tests to execute. -### Examples +This allows you write tests that actually call out to other services, rather than having to mock or stub those services +in your tests. -#### hello-function Module Configuration -[Github link](https://github.com/garden-io/garden/blob/528b141717f718ebe304d2ebde87b85d0c6c5e50/examples/hello-world/services/hello-function/garden.yml) -````yaml -# examples/hello-world/services/hello-function/garden.yml -module: - description: Hello world serverless function - name: hello-function - type: google-cloud-function - functions: - - name: hello-function - entrypoint: helloFunction - tests: - - name: unit - command: [npm, test] - build: - dependencies: - - name: hello-npm-package - copy: - - source: "./" - target: libraries/hello-npm-package/ -```` +Tests can be run via `garden test`, as well as `garden dev`. -#### hello-container Module Configuration -[Github link](https://github.com/garden-io/garden/blob/528b141717f718ebe304d2ebde87b85d0c6c5e50/examples/hello-world/services/hello-container/garden.yml) -```yaml -# examples/hello-world/services/hello-container/garden.yml -module: - description: Hello world container service - type: container - services: - - name: hello-container - command: [npm, start] - ports: - - name: http - containerPort: 8080 - endpoints: - - path: /hello - port: http - healthCheck: - httpGet: - path: /_ah/health - port: http - dependencies: - - hello-function - build: - dependencies: - - hello-npm-package - tests: - - name: unit - command: [npm, test] - - name: integ - command: [npm, run, integ] - dependencies: - - hello-function -``` +## Next steps + +We highly recommend browsing through the [examples directory](https://github.com/garden-io/garden/tree/master/examples) +to see different examples of how projects and modules can be configured. + +Also be sure to look at the configuration [reference](../reference/config.md) for more details on each of the available +configuration keys. diff --git a/docs/introduction/getting-started.md b/docs/introduction/getting-started.md index b6f7cc0081..e583d55819 100644 --- a/docs/introduction/getting-started.md +++ b/docs/introduction/getting-started.md @@ -130,15 +130,15 @@ To later upgrade to the newest version, run `npm install -g -U garden-cli`. ## Using the CLI -With the CLI installed, we can now try out a few commands using the [hello-world](https://github.com/garden-io/garden-examples/tree/master/simple-project) project from our Github [examples repository](https://github.com/garden-io/garden-examples). The example consists of a a couple of simple services. +With the CLI installed, we can now try out a few commands using the [hello-world](https://github.com/garden-io/garden/examples/tree/master/simple-project) project from our Github [examples repository](https://github.com/garden-io/garden/examples). The example consists of a a couple of simple services. _Note: check if Kubernetes is running with `kubectl version`. You should see both a `Client Version` and a `Server Version` in the response. If not, please start it up before proceeding._ Clone the repo and change into the `hello-world` directory: ```sh -$ git clone https://github.com/garden-io/garden-examples.git -$ cd garden-examples/hello-world +$ git clone https://github.com/garden-io/garden/examples.git +$ cd garden/examples/hello-world ``` First, let's check the environment status by running the following from the project root: diff --git a/examples/simple-project-start/services/go-service/webserver/main.go b/examples/simple-project-start/services/go-service/webserver/main.go index 5130b2d49f..e40f941df8 100644 --- a/examples/simple-project-start/services/go-service/webserver/main.go +++ b/examples/simple-project-start/services/go-service/webserver/main.go @@ -1,7 +1,6 @@ package main import ( - "os" "fmt" "net/http" ) diff --git a/examples/simple-project/services/go-service/webserver/main.go b/examples/simple-project/services/go-service/webserver/main.go index 5130b2d49f..e40f941df8 100644 --- a/examples/simple-project/services/go-service/webserver/main.go +++ b/examples/simple-project/services/go-service/webserver/main.go @@ -1,7 +1,6 @@ package main import ( - "os" "fmt" "net/http" ) diff --git a/garden-cli/src/plugins/openfaas.ts b/garden-cli/src/plugins/openfaas.ts index 44866daf5e..45121a25c8 100644 --- a/garden-cli/src/plugins/openfaas.ts +++ b/garden-cli/src/plugins/openfaas.ts @@ -363,7 +363,7 @@ function getK8sProvider(ctx: PluginContext): KubernetesProvider { } function getServicePath(service: OpenFaasService) { - return join("function", service.name) + return join("/", "function", service.name) } async function getInternalGatewayUrl(ctx: PluginContext) { diff --git a/garden-cli/test/src/commands/scan.ts b/garden-cli/test/src/commands/scan.ts index 897b026828..bdf05cc9cc 100644 --- a/garden-cli/test/src/commands/scan.ts +++ b/garden-cli/test/src/commands/scan.ts @@ -1,14 +1,15 @@ -import { join } from "path" import { Garden } from "../../../src/garden" import { ScanCommand } from "../../../src/commands/scan" +import { getExampleProjects } from "../../helpers" describe("ScanCommand", () => { - it("should successfully scan the hello-world project", async () => { - const root = join(__dirname, "..", "..", "..", "..", "examples", "hello-world") - const garden = await Garden.factory(root) - const ctx = garden.getPluginContext() - const command = new ScanCommand() + for (const [name, path] of Object.entries(getExampleProjects())) { + it(`should successfully scan the ${name} project`, async () => { + const garden = await Garden.factory(path) + const ctx = garden.getPluginContext() + const command = new ScanCommand() - await command.action({ garden, ctx, args: {}, opts: {} }) - }) + await command.action({ garden, ctx, args: {}, opts: {} }) + }) + } })