diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index ba10e23cab1..00000000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.gitignore b/.gitignore
index d79f9fde90d..3c6651d7b95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,3 +75,10 @@ tags
# VSCode specific
.vscode
+
+#
+# MAC OS SPECIFIC
+#
+
+# Finder Desktop Service
+.DS_Store
diff --git a/.travis.yml b/.travis.yml
index 50d0a736f80..68081c9cf09 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -130,7 +130,7 @@ jobs:
# scenario of docker devfile url testing needs only Kube config file. So the test has been
# added here just to make sure docker devfile url command test gets a proper kube config file.
# without creating a separate OpenShift cluster.
- name: "devfile catalog, create, push, delete and docker devfile url command integration tests"
+ name: "devfile catalog, create, push, delete, registry and docker devfile url command integration tests"
script:
- ./scripts/oc-cluster.sh
- make bin
@@ -143,6 +143,7 @@ jobs:
- travis_wait make test-cmd-devfile-push
- travis_wait make test-cmd-devfile-watch
- travis_wait make test-cmd-devfile-delete
+ - travis_wait make test-cmd-devfile-registry
- odo logout
- <<: *base-test
@@ -161,7 +162,7 @@ jobs:
- <<: *base-test
stage: test
- name: "docker devfile push and delete command integration tests"
+ name: "docker devfile push, url, catalog, delete command integration tests"
script:
- make bin
- sudo cp odo /usr/bin
diff --git a/Makefile b/Makefile
index 3d6e8636e7a..3914e3da1cf 100644
--- a/Makefile
+++ b/Makefile
@@ -217,6 +217,11 @@ test-cmd-devfile-watch:
.PHONY: test-cmd-devfile-delete
test-cmd-devfile-delete:
ginkgo $(GINKGO_FLAGS) -focus="odo devfile delete command tests" tests/integration/devfile/
+
+# Run odo devfile registry command tests
+.PHONY: test-cmd-devfile-registry
+test-cmd-devfile-registry:
+ ginkgo $(GINKGO_FLAGS) -focus="odo devfile registry command tests" tests/integration/devfile/
# Run odo storage command tests
.PHONY: test-cmd-storage
diff --git a/README.adoc b/README.adoc
index 1097edc0695..e3e91ae9cd0 100644
--- a/README.adoc
+++ b/README.adoc
@@ -2,7 +2,7 @@
+++
[id="readme"]
-= `odo` - Developer-focused CLI for OpenShift
+= `odo` - Developer-focused CLI for OpenShift and Kubernetes
:toc: macro
:toc-title:
:toclevels: 1
@@ -15,7 +15,7 @@ image:https://img.shields.io/github/license/openshift/odo?style=for-the-badge[Li
[[overview]]
== Overview
-`odo` is a fast, iterative, and straightforward CLI tool for developers who write, build, and deploy applications on OpenShift.
+`odo` is a fast, iterative, and straightforward CLI tool for developers who write, build, and deploy applications on OpenShift and Kubernetes.
Existing tools such as `oc` are more operations-focused and require a deep-understanding of Kubernetes and OpenShift concepts. `odo` abstracts away complex Kubernetes and OpenShift concepts for the developer.
@@ -25,11 +25,11 @@ Existing tools such as `oc` are more operations-focused and require a deep-under
`odo` is designed to be simple and concise with the following key features:
* Simple syntax and design centered around concepts familiar to developers, such as projects, applications, and components.
-* Completely client based. No server is required within the OpenShift cluster for deployment.
+* Completely client based. No server is required within the cluster for deployment.
* Official support for Node.js and Java components.
* Partial compatibility with languages and frameworks such as Ruby, Perl, PHP, and Python.
* Detects changes to local code and deploys it to the cluster automatically, giving instant feedback to validate changes in real time.
-* Lists all the available components and services from the {product-title} cluster.
+* Lists all the available components and services from the cluster.
[id="odo-supported-languages-and-images"]
=== Officially supported languages and corresponding container images
@@ -80,13 +80,13 @@ The list of available container images is sourced from the cluster's internal co
To list the available components and associated container images for your cluster:
-. Log in to the {product-title} cluster with {odo-title}:
+. Access your cluster. Authentication with `odo login` for Kubernetes clusters is currently not supported. For OpenShift cluster, you can authenticate with `odo login`:
+
----
$ odo login -u developer -p developer
----
-. List the available {odo-title} supported and unsupported components and corresponding container images:
+. List the available `odo` supported and unsupported components and corresponding container images:
+
----------------------------------------------------
$ odo catalog list components
@@ -184,8 +184,7 @@ Want to try out the odo experimental mode? Please read the link:https://github.c
*Application:* An application consists of multiple microservices or components that work individually to build the entire application.
-*Component:* A component is similar to a microservice. Multiple
-components make up an application. A component has different attributes like storage. `odo` supports multiple component types like nodejs, perl, php, python, and ruby.
+*Component:* A component is similar to a microservice. Multiple components make up an application. A component has different attributes like storage. `odo` supports multiple component types like nodejs, perl, php, python, and ruby.
*Service:* Typically a service is a database or a service that a
component links to or depends on. For example: MariaDB, Jenkins, MySQL.
diff --git a/cmd/odo/odo.go b/cmd/odo/odo.go
index 4431fb1362a..23ec7c820b8 100644
--- a/cmd/odo/odo.go
+++ b/cmd/odo/odo.go
@@ -3,7 +3,6 @@ package main
import (
"flag"
"os"
- "strings"
"github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/odo/cli"
@@ -46,15 +45,6 @@ func main() {
}
}
- // Override the logging level by the value (if set) by the ODO_LOG_LEVEL env
- // The "-v" flag set on command line will take precedence over ODO_LOG_LEVEL env
- v := flag.CommandLine.Lookup("v").Value.String()
- // if the json flag is passed and is valid, we don't turn on ODO_LOG_LEVEL
- jsonFlagValue := flag.CommandLine.Lookup("o").Value.String()
- if level, ok := os.LookupEnv("ODO_LOG_LEVEL"); ok && v == "0" && strings.ToLower(jsonFlagValue) != "json" {
- _ = flag.CommandLine.Set("v", level)
- }
-
// run the completion, in case that the completion was invoked
// and ran as a completion script or handled a flag that passed
// as argument, the Run method will return true,
diff --git a/docs/dev/development.adoc b/docs/dev/development.adoc
index f2c2bdf2283..49f2ffeec87 100644
--- a/docs/dev/development.adoc
+++ b/docs/dev/development.adoc
@@ -513,7 +513,7 @@ Below is working example of how we would implement a "HelloWorld" struct.
machineOutput := GenericSuccess{
TypeMeta: metav1.TypeMeta{
Kind: "HelloWorldExample",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "MyProject",
diff --git a/docs/dev/machine-output.adoc b/docs/dev/machine-output.adoc
index 336f816449c..8adac0d8426 100644
--- a/docs/dev/machine-output.adoc
+++ b/docs/dev/machine-output.adoc
@@ -170,7 +170,7 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "Application",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "app",
"namespace": "myproject",
@@ -189,12 +189,12 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "List",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {},
"items": [
{
"kind": "Application",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "app",
"namespace": "myproject",
@@ -219,7 +219,7 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "Component",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "nodejs-nodejs-ex-xvgz",
"namespace": "foobarz",
@@ -232,12 +232,12 @@ See the below table for a list of all possible machine readable output commands:
"sourceType": "local",
"urls": {
"kind": "List",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {},
"items": [
{
"kind": "url",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "myurl",
"creationTimestamp": null
@@ -254,7 +254,7 @@ See the below table for a list of all possible machine readable output commands:
},
{
"kind": "url",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "json",
"creationTimestamp": null
@@ -271,12 +271,12 @@ See the below table for a list of all possible machine readable output commands:
},
"storages": {
"kind": "List",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {},
"items": [
{
"kind": "storage",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "mystorage",
"creationTimestamp": null
@@ -288,7 +288,7 @@ See the below table for a list of all possible machine readable output commands:
},
{
"kind": "storage",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "mystorage2",
"creationTimestamp": null
@@ -323,12 +323,12 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "List",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {},
"items": [
{
"kind": "Component",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "nodejs-nvnh",
"creationTimestamp": null
@@ -358,12 +358,12 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "List",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {},
"items": [
{
"kind": "Project",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "myproject",
"creationTimestamp": null
@@ -387,7 +387,7 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "storage",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "mystorage",
"creationTimestamp": null
@@ -405,12 +405,12 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "List",
- "apiVersion": "odo.openshift.io/v1aplha1",
+ "apiVersion": "odo.dev/v1aplha1",
"metadata": {},
"items": [
{
"kind": "Storage",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "mystorage",
"creationTimestamp": null
@@ -430,7 +430,7 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "url",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "foobar-8080",
"creationTimestamp": null
@@ -449,12 +449,12 @@ See the below table for a list of all possible machine readable output commands:
----
{
"kind": "List",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {},
"items": [
{
"kind": "url",
- "apiVersion": "odo.openshift.io/v1alpha1",
+ "apiVersion": "odo.dev/v1alpha1",
"metadata": {
"name": "foobar-8080",
"creationTimestamp": null
diff --git a/docs/proposals/odo-debug.md b/docs/proposals/odo-debug.md
index 983ba755354..3fd05b6ff50 100644
--- a/docs/proposals/odo-debug.md
+++ b/docs/proposals/odo-debug.md
@@ -32,7 +32,7 @@ Odo sets up port-forwarding to allow a debugger to connect to the running proces
```yaml
kind: LocalConfig
-apiversion: odo.openshift.io/v1alpha1
+apiversion: odo.dev
ComponentSettings:
Type: nodejs
SourceLocation: ./
@@ -72,7 +72,7 @@ Optional flag, that controls the number of the local port. The value is not stor
##### The `DebugPort` is set in the LocalConfig:
```yaml
kind: LocalConfig
-apiversion: odo.openshift.io/v1alpha1
+apiversion: odo.dev
ComponentSettings:
Type: nodejs
SourceLocation: ./
@@ -89,7 +89,7 @@ ComponentSettings:
##### If the `DebugPort` is NOT set in the LocalConfig:
```yaml
kind: LocalConfig
-apiversion: odo.openshift.io/v1alpha1
+apiversion: odo.dev
ComponentSettings:
Type: nodejs
SourceLocation: ./
diff --git a/docs/public/deploying-a-devfile-using-odo.adoc b/docs/public/deploying-a-devfile-using-odo.adoc
index cb2e0db9dfe..a7bb91469f1 100644
--- a/docs/public/deploying-a-devfile-using-odo.adoc
+++ b/docs/public/deploying-a-devfile-using-odo.adoc
@@ -8,21 +8,21 @@ With a devfile you can describe:
* The source code being used
* Development components such as IDE tools (VSCode) and application runtimes (Yarn / NPM)
-* A list of pre-defined commands that can be ran
+* A list of pre-defined commands that can be run
* Projects to initially clone
Odo takes this devfile and transforms it into a workspace of multiple containers running on OpenShift, Kubernetes or Docker.
-Devfile's are YAML files with a defined structure, take a look at the general https://github.com/redhat-developer/devfile/blob/master/docs/devfile.md[schema] of devfile.
+Devfiles are YAML files with a defined https://github.com/redhat-developer/devfile/blob/master/docs/devfile.md[schema].
== Odo and devfile
-When deploying a devfile using odo, odo will automatically look at the default https://github.com/elsony/devfile-registry[devfile] https://github.com/eclipse/che-devfile-registry/[registries]. Interacting with the devfile registries allows a user to pull a standard `devfile.yaml` and begin development immediately.
+Odo can now create components from devfiles as recorded in registries. Odo automatically consults the default https://github.com/elsony/devfile-registry[devfile] https://github.com/eclipse/che-devfile-registry/[registries] but users can also add their own registries. Devfiles contribute new component types that users can pull to begin development immediately.
An example deployment scenario:
-. `odo create` will look at devfile registry and pull down the `devfile.yaml` file
-. odo push parses and then deploys the component in the following order:
+. `odo create` will consult the recorded devfile registries to offer the user a selection of available component types and pull down the associated `devfile.yaml` file
+. `odo push` parses and then deploys the component in the following order:
.. Parses and validates the YAML file
.. Deploys the development environment to your OpenShift cluster
.. Synchronizes your source code to the containers
@@ -209,7 +209,7 @@ In this example we will be deploying an https://github.com/odo-devfiles/nodejs-e
$ cd
----
-. List the contents of the directory to see that the front end is a Node.js application:
+. List the contents of the directory to confirm that the application is indeed a Node.js® application:
+
[source,sh]
----
@@ -217,7 +217,7 @@ In this example we will be deploying an https://github.com/odo-devfiles/nodejs-e
app LICENSE package.json package-lock.json README.md
----
-. Create a component configuration of Node.js component-type named mynodejs:
+. Create a component configuration using the `nodejs` component-type named `mynodejs`:
+
[source,sh]
----
@@ -304,7 +304,7 @@ In this example, we will be deploying the same Java Spring Boot® component we d
*Prerequisites:* Docker `17.05` or higher installed
-. Enabling the separate pushtarget preference:
+. Enabling a separate push target, using the `pushtarget` preference:
+
[source,sh]
----
@@ -312,9 +312,8 @@ In this example, we will be deploying the same Java Spring Boot® component we d
Global preference was successfully updated
----
+
-You can configure a separate push target by making use of the `pushtarget` preference.
-. Create a component configuration of Spring Boot component-type named mydockerspringboot and download its sample project:
+. Create a component configuration using the `java-spring-boot` component-type named `mydockerspringboot` and download its sample project:
+
[source,sh]
----
@@ -341,7 +340,7 @@ You can configure a separate push target by making use of the `pushtarget` prefe
+
In order to access the docker application, exposed ports are required and automatically generated by odo.
-. Deploy the Spring Boot devfile component to Docker:
+. Deploy the Spring Boot® devfile component to Docker:
+
[source,sh]
----
diff --git a/docs/public/operator-hub.adoc b/docs/public/operator-hub.adoc
new file mode 100644
index 00000000000..b8fd03428bf
--- /dev/null
+++ b/docs/public/operator-hub.adoc
@@ -0,0 +1,271 @@
+:source-highlighter: pygments
+
+# odo integration with Operator Hub
+---
+
+When working in experimental mode, odo provides the ability to work with
+link:https://www.openshift.com/learn/topics/operators[Operators] installed on
+the cluster. It allows listing of Operators, creation of services from CRD
+(Custom Resource Definitions) provided by the Operators, printing the YAML
+definition and providing custom YAML definition to start the service from a
+CRD.
+
+[NOTE]
+====
+Installation of Operators is not a part of odo workflow. It is something that
+your OpenShift/Kubernetes cluster administrator should be able to do for you.
+====
+
+=== Prerequisites
+
+- `odo` is installed.
+- Required Operators are installed in the project/namespace by cluster
+ administrator.
+- Experimental mode is enabled. For every command (other than those for
+ <>) mentioned in this document to work, we
+ first need to enable the experimental mode. This can be done in
+ different ways. Make sure that you have installed latest version of odo and
+ perform any one of the following actions.
+
+* Enable experimental mode in odo preferences:
++
+[source,shell]
+----
+$ odo prefrence set Experimental true
+----
+
+
+* Export the environment variable `ODO_EXPERIMENTAL`:
++
+[source,shell]
+----
+$ export ODO_EXPERIMENTAL=true
+----
+
+* Prefix every command mentioned below with `ODO_EXPERIMENTAL=true`. For
+ example, to list the Operators installed in current project:
++
+[source,shell]
+----
+$ ODO_EXPERIMENTAL=true odo catalog list services
+----
+
+=== [[create-project]]Creating a project
+Create a project to keep your source code, tests, and libraries organized in a
+separate single unit.
+
+1. Log in to the Kubernetes/OpenShift cluster:
++
+[source,shell]
+----
+$ odo login -u developer -p developer
+----
+
+2. Create a project:
++
+[source,shell]
+----
+$ odo project create myproject
+ ✓ Project 'myproject' is ready for use
+ ✓ New project created and now using project : myproject
+----
+
+=== [[list-operators]]Listing the Operators
+
+To list the Operators installed in current project, execute below command:
+
+[source,shell]
+----
+$ odo catalog list services
+----
+
+It will list the
+link:https://docs.openshift.com/container-platform/4.3/operators/olm-what-operators-are.html[Operators]
+and the services, or
+link:https://docs.openshift.com/container-platform/4.3/operators/crds/crd-extending-api-with-crds.html#crd-custom-resource-definitions_crd-extending-api-with-crds[CRD
+(Custom Resource Definitions)], provided by these Operators. For example, we
+have installed etcd and MongoDB Operators and the output we get is like below:
+
+[source,shell]
+----
+$ odo catalog list services
+Operators available in the cluster
+NAME CRDs
+etcdoperator.v0.9.4 EtcdCluster, EtcdBackup, EtcdRestore
+mongodb-enterprise.v1.4.5 MongoDB, MongoDBUser, MongoDBOpsManager
+----
+
+In above output, `etcdoperator.v0.9.4` is the Operator while `EtcdCluster`,
+`EtcdBackup` and `EtcdRestore` are the CRDs provided by this Operator.
+
+To start a service from an Operator, we need the Operator name and name of the
+service (CRD) to start. Note that these name values are case-sensitive.
+
+=== [[dry-run]]Print the YAML used to start a service
+
+odo provides the feature to print the YAML definition of the service (Custom
+Resource or CR) provided by the Operator before starting a service off it. This
+can be done by:
+
+[source,shell]
+----
+$ odo service create --crd --dry-run
+----
+
+For example, to print YAML definition of `EtcdCluster` provided by
+`etcdoperator.v0.9.4` Operator, you would do:
+
+[source,shell]
+----
+$ odo service create etcdoperator.v0.9.4 --crd EtcdCluster --dry-run
+----
+
+You can also redirect the output generated above and modify it before starting
+a service. We will see this in <>.
+
+=== [[create-service]]Create a service from an Operator
+
+[NOTE]
+====
+For the commands mentioned in this section to work properly, you need to make
+sure that the Operator has a valid definition in its `metadata` to start the
+requested service. The commands mentioned here refer the
+`metadata.annotations.alm-examples` of an Operator and use it as-is to start
+the service. If this YAML has placeholder values or sample values that are not
+meant to aid in starting a real service, you will not be able to see a service
+start from it.
+====
+
+To start an `EtcdCluster` service from `etcdoperator.v0.9.4` Operator, you need
+to execute:
+
+[source,shell]
+----
+$ odo service create etcdoperator.v0.9.4 --crd EtcdCluster
+----
+
+This is exactly same command as that shown in <> section above but without the `--dry-run` flag.
+
+At the moment, `odo` is unable to list services started from an Operator. To
+check if the above command succeeded in starting a service, use `kubectl` or
+`oc`:
+
+[source,shell]
+----
+$ kubectl get EtcdCluster
+----
+
+At the time of writing this document, above command worked out of the box
+because, as mentioned in the note, `etcdoperator.v0.9.4` 's definition has a
+valid example for `EtcdCluster` embedded into it. This can be checked by doing:
+
+
+[source,shell]
+----
+$ kubectl get csv/etcdoperator.v0.9.4 -o yaml
+----
+
+and referring to the `alm-examples` section under `annotations` in the
+`metadata` of the `etcdoperator.v0.9.4` Operator.
+
+If you're using OpenShift, you can replace `kubectl` with `oc` in above
+command.
+
+If there is placeholder/invalid data or no data in the aforementioned section
+of the Operator's definition, `odo` won't be able to start the service. As an
+example, refer to the YAML definition of `EtcdBackup` in the
+`etcdoperator.v0.9.4` 's `metadata`:
+
+[source,yaml]
+----
+apiVersion: etcd.database.coreos.com/v1beta2
+kind: EtcdBackup
+metadata:
+ name: example-etcd-cluster-backup
+spec:
+ etcdEndpoints:
+ -
+ s3:
+ awsSecret:
+ path:
+ storageType: S3
+----
+
+Here we can see some placeholder data in the form of ``
+, `` and `` that the user is expected to set to
+appropriate value for the service to start.
+
+On the other hand, `EtcdCluster` 's definition looks like below:
+
+[source,yaml]
+----
+apiVersion: etcd.database.coreos.com/v1beta2
+kind: EtcdCluster
+metadata:
+ name: example
+spec:
+ size: 3
+ version: 3.2.13
+----
+
+There's no placeholder data here and it can thus be used to spin a working
+service from the Operator.
+
+=== [[create-service-from-yaml]]Create service from a YAML file
+
+[NOTE]
+====
+This feature is provided on temporary basis while we work on adding support for
+link:https://github.com/openshift/odo/issues/2785[passing parameters on the
+command line] and link:https://github.com/openshift/odo/issues/2799[using
+interactive mode] to create Operator backed services.
+====
+
+If the YAML definition of the service (or Custom Resource) that you want to
+start has placeholder data in its Operator's `metadata`, you can use
+<> explained above to get the YAML definition,
+replace the placeholder values with correct values and start the service
+using the corrected YAML definition.
+
+For example, if you would like start an `EtcdCluster` service but of a smaller
+size than what's configured by default, you could first fetch the YAML
+definition of the service:
+
+[source,shell]
+----
+$ odo service create etcdoperator.v0.9.4 --crd EtcdCluster --dry-run
+----
+
+and then modify the YAML to below:
+
+[source,yaml]
+.etcd.yaml
+----
+apiVersion: etcd.database.coreos.com/v1beta2
+kind: EtcdCluster
+metadata:
+ name: my-etcd-cluster // <1>
+spec:
+ size: 1 // <2>
+ version: 3.2.13
+----
+<1> We changed the name from `example` to `my-etcd-cluster`
+<2> We reduced the size from `3` to `1`
+
+Now we can use the `etcd.yaml` file above to create a service:
+
+[source,shell]
+----
+$ odo service create --from-file etcd.yaml
+----
+
+This will result in a `EtcdCluster` service with only one pod instead of the
+three pods that it's originally configured to create. This can be checked by
+doing:
+
+[source,shell]
+----
+$ kubectl get pods | grep my-etcd-cluster
+----
diff --git a/pkg/application/application.go b/pkg/application/application.go
index ab206ee662d..a67e7740ef1 100644
--- a/pkg/application/application.go
+++ b/pkg/application/application.go
@@ -14,7 +14,7 @@ import (
)
const (
- appAPIVersion = "odo.openshift.io/v1alpha1"
+ appAPIVersion = "odo.dev/v1alpha1"
appKind = "Application"
appList = "List"
)
diff --git a/pkg/catalog/catalog.go b/pkg/catalog/catalog.go
index 8a4dc6c8ab0..9c605b70cf8 100644
--- a/pkg/catalog/catalog.go
+++ b/pkg/catalog/catalog.go
@@ -7,7 +7,9 @@ import (
"strings"
imagev1 "github.com/openshift/api/image/v1"
+ "github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/occlient"
+ "github.com/openshift/odo/pkg/preference"
"github.com/openshift/odo/pkg/util"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
@@ -15,12 +17,44 @@ import (
"k8s.io/klog"
)
+const (
+ apiVersion = "odo.dev/v1alpha1"
+)
+
// DevfileRegistries contains the links of all devfile registries
var DevfileRegistries = []string{
"https://raw.githubusercontent.com/elsony/devfile-registry/master",
"https://che-devfile-registry.openshift.io/",
}
+// GetDevfileRegistries gets devfile registries from preference file,
+// if registry name is specified return the specific registry, otherwise return all registries
+func GetDevfileRegistries(registryName string) (map[string]string, error) {
+ devfileRegistries := make(map[string]string)
+
+ cfg, err := preference.New()
+ if err != nil {
+ return nil, err
+ }
+
+ if cfg.OdoSettings.RegistryList != nil {
+ for _, registry := range *cfg.OdoSettings.RegistryList {
+ if len(registryName) != 0 {
+ if registryName == registry.Name {
+ devfileRegistries[registry.Name] = registry.URL
+ return devfileRegistries, nil
+ }
+ } else {
+ devfileRegistries[registry.Name] = registry.URL
+ }
+ }
+ } else {
+ return nil, nil
+ }
+
+ return devfileRegistries, nil
+}
+
// GetDevfileIndex loads the devfile registry index.json
func GetDevfileIndex(devfileIndexLink string) ([]DevfileIndexEntry, error) {
var devfileIndex []DevfileIndexEntry
@@ -103,16 +137,26 @@ func IsDevfileComponentSupported(devfile Devfile) bool {
}
// ListDevfileComponents lists all the available devfile components
-func ListDevfileComponents() (DevfileComponentTypeList, error) {
+func ListDevfileComponents(registryName string) (DevfileComponentTypeList, error) {
var catalogDevfileList DevfileComponentTypeList
- catalogDevfileList.DevfileRegistries = DevfileRegistries
+ var err error
+
+ // Get devfile registries
+ catalogDevfileList.DevfileRegistries, err = GetDevfileRegistries(registryName)
+ if err != nil {
+ return catalogDevfileList, err
+ }
+ if catalogDevfileList.DevfileRegistries == nil {
+ return catalogDevfileList, nil
+ }
- for _, devfileRegistry := range DevfileRegistries {
+ for registryName, registryURL := range catalogDevfileList.DevfileRegistries {
// Load the devfile registry index.json
- devfileIndexLink := devfileRegistry + "/devfiles/index.json"
+ devfileIndexLink := registryURL + "/devfiles/index.json"
devfileIndex, err := GetDevfileIndex(devfileIndexLink)
if err != nil {
- return DevfileComponentTypeList{}, err
+ log.Warningf("Registry %s is not set up properly with error: %v", registryName, err)
+ break
}
// 1. Load devfiles that indexed in devfile registry index.json
@@ -122,14 +166,15 @@ func ListDevfileComponents() (DevfileComponentTypeList, error) {
devfileIndexEntryLink := devfileIndexEntry.Links.Link
// Load the devfile
- devfileLink := devfileRegistry + devfileIndexEntryLink
- // TODO: We send http get resquest in this function mutiple times
+ devfileLink := registryURL + devfileIndexEntryLink
+ // TODO: We send http get resquest in this function multiple times
// since devfile registry uses different links to host different devfiles,
// this can reduce the performance especially when we load devfiles from
// big registry. We may need to rethink and optimize this in the future
devfile, err := GetDevfile(devfileLink)
if err != nil {
- return DevfileComponentTypeList{}, err
+ log.Warningf("Registry %s is not set up properly with error: %v", registryName, err)
+ break
}
// Populate devfile component with devfile data and form devfile component list
@@ -139,7 +184,10 @@ func ListDevfileComponents() (DevfileComponentTypeList, error) {
Description: devfileIndexEntry.Description,
Link: devfileIndexEntryLink,
Support: IsDevfileComponentSupported(devfile),
- Registry: devfileRegistry,
+ Registry: Registry{
+ Name: registryName,
+ URL: registryURL,
+ },
}
catalogDevfileList.Items = append(catalogDevfileList.Items, catalogDevfile)
@@ -164,7 +212,7 @@ func ListComponents(client *occlient.Client) (ComponentTypeList, error) {
return ComponentTypeList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
Items: catalogList,
}, nil
@@ -219,7 +267,7 @@ func ListServices(client *occlient.Client) (ServiceTypeList, error) {
return ServiceTypeList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
Items: clusterServiceClasses,
}, nil
@@ -243,7 +291,7 @@ func SearchService(client *occlient.Client, name string) (ServiceTypeList, error
return ServiceTypeList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
Items: result,
}, nil
@@ -274,7 +322,7 @@ func getClusterCatalogServices(client *occlient.Client) ([]ServiceType, error) {
classNames = append(classNames, ServiceType{
TypeMeta: metav1.TypeMeta{
Kind: "ServiceType",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: class.Spec.ExternalName,
@@ -499,7 +547,7 @@ func getBuildersFromImageStreams(imageStreams []imagev1.ImageStream, imageStream
catalogImage := ComponentType{
TypeMeta: metav1.TypeMeta{
Kind: "ComponentType",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: imageStream.Name,
diff --git a/pkg/catalog/catalog_test.go b/pkg/catalog/catalog_test.go
index ad0e3d44588..e201f2685ef 100644
--- a/pkg/catalog/catalog_test.go
+++ b/pkg/catalog/catalog_test.go
@@ -1,13 +1,16 @@
package catalog
import (
+ "io/ioutil"
"net/http"
"net/http/httptest"
+ "os"
"reflect"
"testing"
imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/odo/pkg/occlient"
+ "github.com/openshift/odo/pkg/preference"
"github.com/openshift/odo/pkg/testingutil"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -168,6 +171,67 @@ func TestSliceSupportedTags(t *testing.T) {
}
}
+func TestGetDevfileRegistries(t *testing.T) {
+ tempConfigFile, err := ioutil.TempFile("", "odoconfig")
+ if err != nil {
+ t.Fatal("Fail to create temporary config file")
+ }
+ defer os.Remove(tempConfigFile.Name())
+ defer tempConfigFile.Close()
+ _, err = tempConfigFile.Write([]byte(
+ `kind: Preference
+apiversion: odo.openshift.io/v1alpha1
+OdoSettings:
+ Experimental: true
+ RegistryList:
+ - Name: CheDevfileRegistry
+ URL: https://che-devfile-registry.openshift.io/
+ - Name: DefaultDevfileRegistry
+ URL: https://raw.githubusercontent.com/elsony/devfile-registry/master`,
+ ))
+ if err != nil {
+ t.Error(err)
+ }
+
+ os.Setenv(preference.GlobalConfigEnvName, tempConfigFile.Name())
+ defer os.Unsetenv(preference.GlobalConfigEnvName)
+
+ tests := []struct {
+ name string
+ registryName string
+ want map[string]string
+ }{
+ {
+ name: "Case 1: Test get all devfile registries",
+ registryName: "",
+ want: map[string]string{
+ "CheDevfileRegistry": "https://che-devfile-registry.openshift.io/",
+ "DefaultDevfileRegistry": "https://raw.githubusercontent.com/elsony/devfile-registry/master",
+ },
+ },
+ {
+ name: "Case 2: Test get specific devfile registry",
+ registryName: "CheDevfileRegistry",
+ want: map[string]string{
+ "CheDevfileRegistry": "https://che-devfile-registry.openshift.io/",
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := GetDevfileRegistries(tt.registryName)
+ if err != nil {
+ t.Errorf("Error message is %v", err)
+ }
+
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("Got: %v, want: %v", got, tt.want)
+ }
+ })
+ }
+}
+
func TestGetDevfileIndex(t *testing.T) {
// Start a local HTTP server
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
diff --git a/pkg/catalog/types.go b/pkg/catalog/types.go
index a3266f0d8f6..fd7eef68916 100644
--- a/pkg/catalog/types.go
+++ b/pkg/catalog/types.go
@@ -12,6 +12,12 @@ type ComponentType struct {
Spec ComponentSpec `json:"spec,omitempty"`
}
+// Registry is the main struct of devfile registry
+type Registry struct {
+ Name string
+ URL string
+}
+
// DevfileComponentType is the main struct for devfile catalog components
type DevfileComponentType struct {
Name string
@@ -19,7 +25,7 @@ type DevfileComponentType struct {
Description string
Link string
Support bool
- Registry string
+ Registry Registry
}
// DevfileIndexEntry is the main struct of index.json from devfile registry
@@ -66,7 +72,7 @@ type ComponentTypeList struct {
// DevfileComponentTypeList lists all the DevfileComponentType's
type DevfileComponentTypeList struct {
- DevfileRegistries []string
+ DevfileRegistries map[string]string
Items []DevfileComponentType
}
diff --git a/pkg/component/component.go b/pkg/component/component.go
index 6d4e39342fb..ba0bc9f5405 100644
--- a/pkg/component/component.go
+++ b/pkg/component/component.go
@@ -45,6 +45,8 @@ const componentRandomNamePartsMaxLen = 12
const componentNameMaxRetries = 3
const componentNameMaxLen = -1
+const apiVersion = "odo.dev/v1alpha1"
+
// GetComponentDir returns source repo name
// Parameters:
// path: git url or source path or binary path
@@ -1426,7 +1428,7 @@ func getMachineReadableFormat(componentName, componentType string) Component {
return Component{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: componentName,
@@ -1447,7 +1449,7 @@ func GetMachineReadableFormatForList(components []Component) ComponentList {
return ComponentList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ListMeta: metav1.ListMeta{},
Items: components,
diff --git a/pkg/component/component_full_description.go b/pkg/component/component_full_description.go
index 5ef8c88880d..8b92dfd725a 100644
--- a/pkg/component/component_full_description.go
+++ b/pkg/component/component_full_description.go
@@ -95,7 +95,7 @@ func (cfd *ComponentFullDescription) fillEmptyFields(componentDesc Component, co
}
if len(cfd.APIVersion) <= 0 {
- cfd.APIVersion = "odo.openshift.io/v1alpha1"
+ cfd.APIVersion = apiVersion
}
if len(cfd.Spec.App) <= 0 {
diff --git a/pkg/component/component_test.go b/pkg/component/component_test.go
index 3af0861206f..7ef6883f4b9 100644
--- a/pkg/component/component_test.go
+++ b/pkg/component/component_test.go
@@ -284,7 +284,7 @@ func TestList(t *testing.T) {
output: ComponentList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ListMeta: metav1.ListMeta{},
Items: []Component{
@@ -314,7 +314,7 @@ func TestList(t *testing.T) {
output: ComponentList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ListMeta: metav1.ListMeta{},
Items: []Component{
@@ -545,7 +545,7 @@ func Test_getMachineReadableFormat(t *testing.T) {
want: Component{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "frontend",
@@ -583,7 +583,7 @@ func Test_getMachineReadableFormatForList(t *testing.T) {
{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "frontend",
@@ -596,7 +596,7 @@ func Test_getMachineReadableFormatForList(t *testing.T) {
{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "backend",
@@ -611,14 +611,14 @@ func Test_getMachineReadableFormatForList(t *testing.T) {
want: ComponentList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ListMeta: metav1.ListMeta{},
Items: []Component{
{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "frontend",
@@ -631,7 +631,7 @@ func Test_getMachineReadableFormatForList(t *testing.T) {
{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "backend",
@@ -798,7 +798,7 @@ func TestUnlinkComponents(t *testing.T) {
componentList := ComponentList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ListMeta: metav1.ListMeta{},
Items: tt.childComponents,
@@ -866,7 +866,7 @@ func getFakeComponent(compName, namespace, appName, compType string, state State
return Component{
TypeMeta: metav1.TypeMeta{
Kind: "Component",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: compName,
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 8c4381a32c2..9f8bbb149a4 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -23,7 +23,7 @@ const (
localConfigEnvName = "LOCALODOCONFIG"
configFileName = "config.yaml"
localConfigKind = "LocalConfig"
- localConfigAPIVersion = "odo.openshift.io/v1alpha1"
+ localConfigAPIVersion = "odo.dev/v1alpha1"
// DefaultDebugPort is the default port used for debugging on remote pod
DefaultDebugPort = 5858
)
diff --git a/pkg/devfile/adapters/common/types.go b/pkg/devfile/adapters/common/types.go
index 8b95ee53dea..3a4cb3882fb 100644
--- a/pkg/devfile/adapters/common/types.go
+++ b/pkg/devfile/adapters/common/types.go
@@ -8,6 +8,7 @@ import (
// AdapterContext is a construct that is common to all adapters
type AdapterContext struct {
ComponentName string // ComponentName is the odo component name, it is NOT related to any devfile components
+ Context string // Context is the given directory containing the source code and configs
Devfile devfileParser.DevfileObj // Devfile is the object returned by the Devfile parser
}
diff --git a/pkg/devfile/adapters/common/utils.go b/pkg/devfile/adapters/common/utils.go
index e395bc39d6c..7a754804aa4 100644
--- a/pkg/devfile/adapters/common/utils.go
+++ b/pkg/devfile/adapters/common/utils.go
@@ -29,7 +29,7 @@ const (
// Default Image that will be used containing the supervisord binary and assembly scripts
// use GetBootstrapperImage() function instead of this variable
- defaultBootstrapperImage = "registry.access.redhat.com/openshiftdo/odo-init-image-rhel7:1.1.2"
+ defaultBootstrapperImage = "registry.access.redhat.com/openshiftdo/odo-init-image-rhel7:1.1.3"
// SupervisordControlCommand sub command which stands for control
SupervisordControlCommand = "ctl"
diff --git a/pkg/devfile/adapters/docker/component/adapter.go b/pkg/devfile/adapters/docker/component/adapter.go
index 9237f120b98..5acf6c468a6 100644
--- a/pkg/devfile/adapters/docker/component/adapter.go
+++ b/pkg/devfile/adapters/docker/component/adapter.go
@@ -2,6 +2,7 @@ package component
import (
"fmt"
+ "strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/mount"
@@ -155,25 +156,53 @@ func (a Adapter) Delete(labels map[string]string) error {
return errors.New("unable to delete component without a component label")
}
- list, err := a.Client.GetContainerList()
+ containers, err := a.Client.GetContainerList()
if err != nil {
return errors.Wrap(err, "unable to retrieve container list for delete operation")
}
- componentContainer := a.Client.GetContainersByComponent(componentName, list)
+ // A unique list of volumes NOT to delete, because they are still mapped into other containers.
+ // map key is volume name.
+ volumesNotToDelete := map[string]string{}
+
+ // Go through the containers which are NOT part of this component, and make a list of all
+ // their volumes so we don't delete them.
+ for _, container := range containers {
+
+ if container.Labels["component"] == componentName {
+ continue
+ }
+
+ for _, mount := range container.Mounts {
+ volumesNotToDelete[mount.Name] = mount.Name
+ }
+ }
+
+ componentContainer := a.Client.GetContainersByComponent(componentName, containers)
if len(componentContainer) == 0 {
return errors.Errorf("the component %s doesn't exist", a.ComponentName)
}
- // Get all volumes that match our component label
- volumeLabels := utils.GetProjectVolumeLabels(componentName)
- vols, err := a.Client.GetVolumesByLabel(volumeLabels)
+ allVolumes, err := a.Client.GetVolumes()
if err != nil {
- return errors.Wrapf(err, "unable to retrieve source volume for component "+componentName)
+ return errors.Wrapf(err, "unable to retrieve list of all Docker volumes")
}
- if len(vols) == 0 {
- return fmt.Errorf("unable to find source volume for component %s", componentName)
+
+ // Look for this component's volumes that contain either a storage-name label or a type label
+ var vols []types.Volume
+ for _, vol := range allVolumes {
+
+ if vol.Labels["component"] == componentName {
+
+ if snVal := vol.Labels["storage-name"]; len(strings.TrimSpace(snVal)) > 0 {
+ vols = append(vols, vol)
+ } else {
+ if typeVal := vol.Labels["type"]; typeVal == "projects" {
+ vols = append(vols, vol)
+ }
+ }
+ }
}
// A unique list of volumes to delete; map key is volume name.
@@ -198,10 +227,20 @@ func (a Adapter) Delete(labels map[string]string) error {
}
for _, vol := range vols {
+
+ // Don't delete any volumes which are mapped into other containers
+ if _, exists := volumesNotToDelete[vol.Name]; exists {
+ klog.V(4).Infof("Skipping volume %s as it is mapped into a non-odo managed container", vol.Name)
+ continue
+ }
+
// If the volume was found to be attached to the component's container, then add the volume
// to the deletion list.
if _, ok := volumeNames[vol.Name]; ok {
+ klog.V(4).Infof("Adding volume %s to deletion list", vol.Name)
volumesToDelete[vol.Name] = vol.Name
+ } else {
+ klog.V(4).Infof("Skipping volume %s as it was not attached to the component's container", vol.Name)
}
}
}
diff --git a/pkg/devfile/adapters/docker/component/adapter_test.go b/pkg/devfile/adapters/docker/component/adapter_test.go
index c8f4864c0f5..30a502e1ff5 100644
--- a/pkg/devfile/adapters/docker/component/adapter_test.go
+++ b/pkg/devfile/adapters/docker/component/adapter_test.go
@@ -291,3 +291,315 @@ func TestAdapterDelete(t *testing.T) {
})
}
}
+
+func TestAdapterDeleteVolumes(t *testing.T) {
+
+ // Convenience func to create a mock ODO-style container with the given volume mounts
+ containerWithMount := func(componentName string, mountPoints []types.MountPoint) types.Container {
+
+ return types.Container{
+ ID: componentName,
+ Labels: map[string]string{
+ "component": componentName,
+ },
+ Mounts: mountPoints,
+ }
+ }
+
+ componentName := "my-component"
+ anotherComponentName := "other-component"
+
+ // The purpose of these tests is to verify the correctness of container deletion, such as:
+ // - Only volumes that match the format of an ODO-managed volume (storage or source) are deleted
+ // - Ensure that bind mounts are never deleted
+ // - Ensure that other component's volumes are never deleted
+ // - Ensure that volumes that have only the exact source/storage labels format are deleted
+
+ tests := []struct {
+ name string
+ containers []types.Container
+ volumes []*types.Volume
+ expectToDelete []string
+ }{
+ {
+ name: "Case 1: Should delete both storage and source mount",
+ containers: []types.Container{
+ containerWithMount(componentName,
+ []types.MountPoint{
+ {
+ Name: "my-src-mount",
+ Type: mount.TypeVolume,
+ },
+ {
+ Name: "my-storage-mount",
+ Type: mount.TypeVolume,
+ },
+ }),
+ },
+ volumes: []*types.Volume{
+ {
+ Name: "my-src-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "type": "projects",
+ },
+ },
+ {
+ Name: "my-storage-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "storage-name": "anyval",
+ },
+ },
+ },
+ expectToDelete: []string{
+ "my-src-mount",
+ "my-storage-mount",
+ },
+ },
+ {
+ name: "Case 2: Should delete storage mount alone",
+ containers: []types.Container{
+ containerWithMount(componentName,
+ []types.MountPoint{
+ {
+ Name: "my-storage-mount",
+ Type: mount.TypeVolume,
+ },
+ }),
+ },
+ volumes: []*types.Volume{
+ {
+ Name: "my-storage-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "storage-name": "anyval",
+ },
+ },
+ },
+ expectToDelete: []string{
+ "my-storage-mount",
+ },
+ },
+ {
+ name: "Case 3: Should not delete a bind mount even if it matches src volume labels",
+ containers: []types.Container{
+ containerWithMount(componentName,
+ []types.MountPoint{
+ {
+ Name: "my-src-mount",
+ Type: mount.TypeBind,
+ },
+ }),
+ },
+
+ volumes: []*types.Volume{
+ {
+ Name: "my-src-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "type": "projects",
+ },
+ },
+ },
+ expectToDelete: []string{},
+ },
+ {
+ name: "Case 4: Should not try to delete other component's volumes",
+ containers: []types.Container{
+ containerWithMount(componentName,
+ []types.MountPoint{
+ {
+ Name: "my-src-mount",
+ Type: mount.TypeVolume,
+ },
+ {
+ Name: "my-storage-mount",
+ Type: mount.TypeVolume,
+ },
+ }),
+ containerWithMount(anotherComponentName,
+ []types.MountPoint{
+ {
+ Name: "my-src-mount-other-component",
+ Type: mount.TypeVolume,
+ },
+ {
+ Name: "my-storage-mount-other-component",
+ Type: mount.TypeVolume,
+ },
+ }),
+ },
+ volumes: []*types.Volume{
+ {
+ Name: "my-src-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "type": "projects",
+ },
+ },
+ {
+ Name: "my-storage-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "storage-name": "anyval",
+ },
+ },
+ {
+ Name: "my-src-mount-other-component",
+ Labels: map[string]string{
+ "component": anotherComponentName,
+ "type": "projects",
+ },
+ },
+ {
+ Name: "my-storage-mount-other-component",
+ Labels: map[string]string{
+ "component": anotherComponentName,
+ "storage-name": "anyval",
+ },
+ },
+ },
+ expectToDelete: []string{
+ "my-src-mount",
+ "my-storage-mount",
+ },
+ },
+ {
+ name: "Case 5: Should not try to delete a component's non-ODO volumes, even if the format is very close to ODO",
+ containers: []types.Container{containerWithMount("my-component",
+ []types.MountPoint{
+ {
+ Name: "my-src-mount",
+ Type: mount.TypeVolume,
+ },
+ {
+ Name: "my-storage-mount",
+ Type: mount.TypeVolume,
+ },
+ {
+ Name: "another-volume-1",
+ Type: mount.TypeVolume,
+ },
+ {
+ Name: "another-volume-2",
+ Type: mount.TypeVolume,
+ },
+ })},
+ volumes: []*types.Volume{
+ {
+ Name: "my-src-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "type": "projects",
+ },
+ },
+ {
+ Name: "my-storage-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "storage-name": "anyval",
+ },
+ },
+ {
+ Name: "another-volume-1",
+ Labels: map[string]string{
+ "component": componentName,
+ "type": "projects-but-not-really",
+ },
+ },
+ {
+ Name: "another-volume-2",
+ Labels: map[string]string{
+ "component": componentName,
+ "storage-name-but-not-really": "anyval",
+ },
+ },
+ },
+ expectToDelete: []string{
+ "my-src-mount",
+ "my-storage-mount",
+ },
+ },
+ {
+ name: "Case 6: Should not delete a volume that is mounted into another container",
+ containers: []types.Container{
+
+ containerWithMount("my-component",
+ []types.MountPoint{
+ {
+ Name: "my-storage-mount",
+ Type: mount.TypeVolume,
+ },
+ }),
+
+ containerWithMount("a-non-odo-container-for-example",
+ []types.MountPoint{
+ {
+ Name: "my-storage-mount",
+ Type: mount.TypeVolume,
+ },
+ }),
+ },
+ volumes: []*types.Volume{
+ {
+ Name: "my-storage-mount",
+ Labels: map[string]string{
+ "component": componentName,
+ "storage-name": "anyval",
+ },
+ },
+ },
+ expectToDelete: []string{},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ devObj := devfileParser.DevfileObj{
+ Data: testingutil.TestDevfileData{
+ ComponentType: "nodejs",
+ },
+ }
+
+ adapterCtx := adaptersCommon.AdapterContext{
+ ComponentName: componentName,
+ Devfile: devObj,
+ }
+
+ fkclient, mockDockerClient := lclient.FakeNewMockClient(ctrl)
+
+ a := Adapter{
+ Client: *fkclient,
+ AdapterContext: adapterCtx,
+ }
+
+ arg := map[string]string{
+ "component": componentName,
+ }
+
+ mockDockerClient.EXPECT().ContainerList(gomock.Any(), gomock.Any()).Return(tt.containers, nil)
+
+ mockDockerClient.EXPECT().ContainerRemove(gomock.Any(), componentName, gomock.Any()).Return(nil)
+
+ mockDockerClient.EXPECT().VolumeList(gomock.Any(), gomock.Any()).Return(volumeTypes.VolumeListOKBody{
+ Volumes: tt.volumes,
+ }, nil)
+
+ for _, deleteExpected := range tt.expectToDelete {
+ mockDockerClient.EXPECT().VolumeRemove(gomock.Any(), deleteExpected, gomock.Any()).Return(nil)
+ }
+
+ err := a.Delete(arg)
+ if err != nil {
+ t.Errorf("Delete() unexpected error = %v", err)
+ }
+
+ })
+
+ }
+
+}
diff --git a/pkg/devfile/adapters/docker/component/utils.go b/pkg/devfile/adapters/docker/component/utils.go
index 29424496d40..9d698278238 100644
--- a/pkg/devfile/adapters/docker/component/utils.go
+++ b/pkg/devfile/adapters/docker/component/utils.go
@@ -24,8 +24,10 @@ import (
"github.com/openshift/odo/pkg/log"
)
-// LocalhostIP is the IP address for localhost
-var LocalhostIP = "127.0.0.1"
+const (
+ localhostIP = "127.0.0.1"
+ projectSourceVolumeName = "odo-project-source"
+)
func (a Adapter) createComponent() (err error) {
componentName := a.ComponentName
@@ -41,7 +43,7 @@ func (a Adapter) createComponent() (err error) {
}
if len(projectVols) == 0 {
// A source volume needs to be created
- projectVolumeName, err = storage.GenerateVolNameFromDevfileVol("odo-project-source", a.ComponentName)
+ projectVolumeName, err = storage.GenerateVolName(projectSourceVolumeName, a.ComponentName)
if err != nil {
return errors.Wrapf(err, "Unable to generate project source volume name for component %s", componentName)
}
@@ -154,7 +156,7 @@ func (a Adapter) updateComponent() (componentExists bool, err error) {
return componentExists, errors.Wrapf(err, "unable to get the container config for component %s", componentName)
}
- portMap, err := getPortMap(comp.Endpoints, false)
+ portMap, err := getPortMap(a.Context, comp.Endpoints, false)
if err != nil {
return componentExists, errors.Wrapf(err, "unable to get the port map from env.yaml file for component %s", componentName)
}
@@ -271,7 +273,7 @@ func (a Adapter) generateAndGetContainerConfig(componentName string, comp versio
func (a Adapter) generateAndGetHostConfig(endpoints []versionsCommon.DockerimageEndpoint) (container.HostConfig, error) {
// Convert the port bindings from env.yaml and generate docker host config
- portMap, err := getPortMap(endpoints, true)
+ portMap, err := getPortMap(a.Context, endpoints, true)
if err != nil {
return container.HostConfig{}, err
}
@@ -284,12 +286,21 @@ func (a Adapter) generateAndGetHostConfig(endpoints []versionsCommon.Dockerimage
return hostConfig, nil
}
-func getPortMap(endpoints []versionsCommon.DockerimageEndpoint, show bool) (nat.PortMap, error) {
+func getPortMap(context string, endpoints []versionsCommon.DockerimageEndpoint, show bool) (nat.PortMap, error) {
// Convert the exposed and internal port pairs saved in env.yaml file to PortMap
// Todo: Use context to get the approraite envinfo after context is supported in experimental mode
portmap := nat.PortMap{}
- dir, err := os.Getwd()
+ var dir string
+ var err error
+ if context == "" {
+ dir, err = os.Getwd()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ dir = context
+ }
if err != nil {
return portmap, err
}
@@ -309,12 +320,12 @@ func getPortMap(endpoints []versionsCommon.DockerimageEndpoint, show bool) (nat.
}
portmap[port] = []nat.PortBinding{
nat.PortBinding{
- HostIP: LocalhostIP,
+ HostIP: localhostIP,
HostPort: strconv.Itoa(url.ExposedPort),
},
}
if show {
- log.Successf("URL %v:%v created", LocalhostIP, url.ExposedPort)
+ log.Successf("URL %v:%v created", localhostIP, url.ExposedPort)
}
} else if url.ExposedPort > 0 && len(endpoints) > 0 && !common.IsPortPresent(endpoints, url.Port) {
return portmap, fmt.Errorf("Error creating url: odo url config's port is not present in the devfile. Please re-create odo url with the new devfile port")
diff --git a/pkg/devfile/adapters/docker/component/utils_test.go b/pkg/devfile/adapters/docker/component/utils_test.go
index ac0305fc96f..a557c551c26 100644
--- a/pkg/devfile/adapters/docker/component/utils_test.go
+++ b/pkg/devfile/adapters/docker/component/utils_test.go
@@ -333,7 +333,7 @@ func TestGenerateAndGetHostConfig(t *testing.T) {
expectResult: nat.PortMap{
"8080/tcp": []nat.PortBinding{
{
- HostIP: LocalhostIP,
+ HostIP: localhostIP,
HostPort: "65432",
},
},
@@ -356,19 +356,19 @@ func TestGenerateAndGetHostConfig(t *testing.T) {
expectResult: nat.PortMap{
"8080/tcp": []nat.PortBinding{
{
- HostIP: LocalhostIP,
+ HostIP: localhostIP,
HostPort: "65432",
},
},
"9090/tcp": []nat.PortBinding{
{
- HostIP: LocalhostIP,
+ HostIP: localhostIP,
HostPort: "54321",
},
},
"9080/tcp": []nat.PortBinding{
{
- HostIP: LocalhostIP,
+ HostIP: localhostIP,
HostPort: "45678",
},
},
diff --git a/pkg/devfile/adapters/docker/storage/utils.go b/pkg/devfile/adapters/docker/storage/utils.go
index 7fbe2f21413..60bf74d5c8a 100644
--- a/pkg/devfile/adapters/docker/storage/utils.go
+++ b/pkg/devfile/adapters/docker/storage/utils.go
@@ -54,15 +54,20 @@ func Create(Client *lclient.Client, name, componentName, dockerVolName string) (
return &vol, nil
}
-// GenerateVolNameFromDevfileVol generates a Docker volume name from the Devfile volume name and component name
-func GenerateVolNameFromDevfileVol(volName, componentName string) (string, error) {
+// GenerateVolName generates a Docker volume name from the Devfile volume name and component name
+func GenerateVolName(volName, componentName string) (string, error) {
+
+ if volName == "" {
+ err := errors.New("unable to generate volume name with an empty name")
+ return "", err
+ }
dockerVolName := fmt.Sprintf("%v-%v", volName, componentName)
dockerVolName = util.TruncateString(dockerVolName, volNameMaxLength)
randomChars := util.GenerateRandomString(4)
dockerVolName, err := util.NamespaceOpenShiftObject(dockerVolName, randomChars)
if err != nil {
- return "", errors.Wrapf(err, "unable to create namespaced name")
+ return "", errors.Wrapf(err, "unable to create namespaced name for volume %s", volName)
}
return dockerVolName, nil
@@ -109,7 +114,7 @@ func ProcessVolumes(client *lclient.Client, componentName string, componentAlias
// Generate the volume Names
klog.V(3).Infof("Generating Docker volumes name for %v", *vol.Name)
- generatedDockerVolName, err := GenerateVolNameFromDevfileVol(*vol.Name, componentName)
+ generatedDockerVolName, err := GenerateVolName(*vol.Name, componentName)
if err != nil {
return nil, nil, err
}
diff --git a/pkg/devfile/adapters/docker/storage/utils_test.go b/pkg/devfile/adapters/docker/storage/utils_test.go
index 07de602ab99..6030772914d 100644
--- a/pkg/devfile/adapters/docker/storage/utils_test.go
+++ b/pkg/devfile/adapters/docker/storage/utils_test.go
@@ -1,6 +1,7 @@
package storage
import (
+ "strings"
"testing"
"github.com/openshift/odo/pkg/devfile/adapters/common"
@@ -331,3 +332,54 @@ func TestProcessVolumes(t *testing.T) {
}
}
+
+func TestGenerateVolName(t *testing.T) {
+
+ tests := []struct {
+ name string
+ volName string
+ cmpName string
+ wantVolName string
+ wantErr bool
+ }{
+ {
+ name: "Case 1: Valid volume and component name",
+ volName: "myVol",
+ cmpName: "myCmp",
+ wantVolName: "myVol-myCmp",
+ wantErr: false,
+ },
+ {
+ name: "Case 2: Valid volume name, empty component name",
+ volName: "myVol",
+ cmpName: "",
+ wantVolName: "myVol-",
+ wantErr: false,
+ },
+ {
+ name: "Case 3: Long Valid volume and component name",
+ volName: "myVolmyVolmyVolmyVolmyVolmyVolmyVolmyVolmyVol",
+ cmpName: "myCmpmyCmpmyCmpmyCmpmyCmpmyCmpmyCmpmyCmpmyCmp",
+ wantVolName: "myVolmyVolmyVolmyVolmyVolmyVolmyVolmyVolmyVol-",
+ wantErr: false,
+ },
+ {
+ name: "Case 4: Empty volume name",
+ volName: "",
+ cmpName: "myCmp",
+ wantVolName: "",
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ generatedVolName, err := GenerateVolName(tt.volName, tt.cmpName)
+ if !tt.wantErr && err != nil {
+ t.Errorf("TestGenerateVolName error: unexpected error when generating volume name: %v", err)
+ } else if !tt.wantErr && !strings.Contains(generatedVolName, tt.wantVolName) {
+ t.Errorf("TestGenerateVolName error: generating volume name does not semi match wanted volume name, wanted: %s got: %s", tt.wantVolName, generatedVolName)
+ }
+ })
+ }
+
+}
diff --git a/pkg/devfile/adapters/docker/utils/utils.go b/pkg/devfile/adapters/docker/utils/utils.go
index 5125fc66e39..aab022897f7 100644
--- a/pkg/devfile/adapters/docker/utils/utils.go
+++ b/pkg/devfile/adapters/docker/utils/utils.go
@@ -11,6 +11,7 @@ import (
"github.com/docker/docker/api/types/mount"
adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common"
+ "github.com/openshift/odo/pkg/devfile/adapters/docker/storage"
"github.com/openshift/odo/pkg/devfile/parser/data/common"
"github.com/openshift/odo/pkg/lclient"
"github.com/openshift/odo/pkg/log"
@@ -23,6 +24,7 @@ import (
const (
supervisordVolume = "supervisord"
projectsVolume = "projects"
+ volume = "vol"
)
// ComponentExists checks if Docker containers labeled with the specified component name exists
@@ -234,17 +236,26 @@ func UpdateComponentWithSupervisord(comp *common.DevfileComponent, runCommand co
// CreateAndInitSupervisordVolume creates the supervisord volume and initializes
// it with supervisord bootstrap image - assembly files and supervisord binary
func CreateAndInitSupervisordVolume(client lclient.Client) (string, error) {
+ log.Info("\nInitialization")
+ s := log.Spinner("Initializing the component")
+ defer s.End(false)
+
+ supervisordVolumeName, err := storage.GenerateVolName(adaptersCommon.SupervisordVolumeName, volume)
+ if err != nil {
+ return "", errors.Wrapf(err, "unable to generate volume name for supervisord")
+ }
+
supervisordLabels := GetSupervisordVolumeLabels()
- supervisordVolume, err := client.CreateVolume(adaptersCommon.SupervisordVolumeName, supervisordLabels)
+ _, err = client.CreateVolume(supervisordVolumeName, supervisordLabels)
if err != nil {
return "", errors.Wrapf(err, "Unable to create supervisord volume for component")
}
- supervisordVolumeName := supervisordVolume.Name
err = StartBootstrapSupervisordInitContainer(client, supervisordVolumeName)
if err != nil {
return "", errors.Wrapf(err, "Unable to start supervisord container for component")
}
+ s.End(true)
return supervisordVolumeName, nil
}
diff --git a/pkg/devfile/adapters/helper.go b/pkg/devfile/adapters/helper.go
index 7832778f0c0..d375edf3957 100644
--- a/pkg/devfile/adapters/helper.go
+++ b/pkg/devfile/adapters/helper.go
@@ -13,10 +13,11 @@ import (
)
// NewPlatformAdapter returns a Devfile adapter for the targeted platform
-func NewPlatformAdapter(componentName string, devObj devfileParser.DevfileObj, platformContext interface{}) (PlatformAdapter, error) {
+func NewPlatformAdapter(componentName string, context string, devObj devfileParser.DevfileObj, platformContext interface{}) (PlatformAdapter, error) {
adapterContext := common.AdapterContext{
ComponentName: componentName,
+ Context: context,
Devfile: devObj,
}
diff --git a/pkg/kclient/fake/ingress.go b/pkg/kclient/fake/ingress.go
index e525119954c..6de515cb489 100644
--- a/pkg/kclient/fake/ingress.go
+++ b/pkg/kclient/fake/ingress.go
@@ -38,7 +38,7 @@ func GetIngressListWithMultiple(componentName string) *extensionsv1.IngressList
labels.URLLabel: "example-1",
},
},
- Spec: *kclient.GenerateIngressSpec(kclient.IngressParameter{ServiceName: "example-1", PortNumber: intstr.FromInt(8080)}),
+ Spec: *kclient.GenerateIngressSpec(kclient.IngressParameter{ServiceName: "example-1", PortNumber: intstr.FromInt(9090)}),
},
},
}
diff --git a/pkg/lclient/storage.go b/pkg/lclient/storage.go
index 7289ffd78b7..648f6019c9f 100644
--- a/pkg/lclient/storage.go
+++ b/pkg/lclient/storage.go
@@ -40,3 +40,18 @@ func (dc *Client) GetVolumesByLabel(labels map[string]string) ([]types.Volume, e
return volumes, nil
}
+
+// GetVolumes returns the list of all volumes
+func (dc *Client) GetVolumes() ([]types.Volume, error) {
+ var volumes []types.Volume
+ volumeList, err := dc.Client.VolumeList(dc.Context, filters.Args{})
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get list of docker volumes")
+ }
+
+ for _, vol := range volumeList.Volumes {
+ volumes = append(volumes, *vol)
+ }
+
+ return volumes, nil
+}
diff --git a/pkg/lclient/storage_test.go b/pkg/lclient/storage_test.go
index 8e49cf86c1a..a6b159d1919 100644
--- a/pkg/lclient/storage_test.go
+++ b/pkg/lclient/storage_test.go
@@ -5,6 +5,8 @@ import (
"testing"
"github.com/docker/docker/api/types"
+ volume "github.com/docker/docker/api/types/volume"
+ gomock "github.com/golang/mock/gomock"
)
func TestCreateVolume(t *testing.T) {
@@ -150,3 +152,63 @@ func TestGetVolumesByLabel(t *testing.T) {
})
}
}
+
+func TestGetVolumes(t *testing.T) {
+
+ // removePointer is a utility function to convert []*types.Volume to []types.Volume, to allow use of reflect.DeepEqual
+ removePointer := func(input []*types.Volume) []types.Volume {
+ var result []types.Volume
+
+ for _, ptr := range input {
+ if ptr != nil {
+ result = append(result, *ptr)
+ }
+ }
+
+ return result
+ }
+
+ tests := []struct {
+ name string
+ wantVolumes []*types.Volume
+ }{
+ {
+ name: "GetVolumes should return empty volume list",
+ wantVolumes: []*types.Volume{},
+ },
+ {
+ name: "GetVolume should return a single volume",
+ wantVolumes: []*types.Volume{{Name: "One"}},
+ },
+ {
+ name: "GetVolume should return multiple volumes",
+ wantVolumes: []*types.Volume{{Name: "Multiple-1"}, {Name: "Multiple-2"}},
+ },
+ }
+
+ for _, tt := range tests {
+
+ t.Run(tt.name, func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ client, mockDockerClient := FakeNewMockClient(ctrl)
+
+ mockDockerClient.EXPECT().VolumeList(gomock.Any(), gomock.Any()).Return(volume.VolumeListOKBody{
+ Volumes: tt.wantVolumes,
+ }, nil)
+
+ vols, err := client.GetVolumes()
+ if err != nil {
+ t.Errorf("GetVolumes returned an unexpected error %v", err)
+ }
+
+ wanted := removePointer(tt.wantVolumes)
+ if !reflect.DeepEqual(vols, wanted) {
+ t.Errorf("expected %v, wanted %v", vols, wanted)
+ }
+
+ })
+ }
+
+}
diff --git a/pkg/machineoutput/types.go b/pkg/machineoutput/types.go
index cb288505c04..d2603d4180f 100644
--- a/pkg/machineoutput/types.go
+++ b/pkg/machineoutput/types.go
@@ -13,7 +13,7 @@ import (
const Kind = "Error"
// APIVersion is the current API version we are using
-const APIVersion = "odo.openshift.io/v1alpha1"
+const APIVersion = "odo.dev/v1alpha1"
// GenericError for machine readable output error messages
type GenericError struct {
diff --git a/pkg/occlient/occlient.go b/pkg/occlient/occlient.go
index ec55576530c..39b2d7efb81 100644
--- a/pkg/occlient/occlient.go
+++ b/pkg/occlient/occlient.go
@@ -1686,14 +1686,14 @@ func (c *Client) UpdateDCAnnotations(dcName string, annotations map[string]strin
func removeTracesOfSupervisordFromDC(dc *appsv1.DeploymentConfig) error {
dcName := dc.Name
- found := removeVolumeFromDC(getAppRootVolumeName(dcName), dc)
- if !found {
- return errors.New("unable to find volume in dc with name: " + dcName)
+ err := removeVolumeFromDC(getAppRootVolumeName(dcName), dc)
+ if err != nil {
+ return err
}
- found = removeVolumeMountsFromDC(getAppRootVolumeName(dcName), dc)
- if !found {
- return errors.New("unable to find volume mount in dc with name: " + dcName)
+ err = removeVolumeMountsFromDC(getAppRootVolumeName(dcName), dc)
+ if err != nil {
+ return err
}
// remove the one bootstrapped init container
@@ -2721,15 +2721,18 @@ func (c *Client) RemoveVolumeFromDeploymentConfig(pvc string, dcName string) err
return fmt.Errorf("found more than one volume for PVC %v in DC %v, expected one", pvc, dc.Name)
}
volumeName := volumeNames[0]
+
// Remove volume if volume exists in Deployment Config
- if !removeVolumeFromDC(volumeName, dc) {
- return fmt.Errorf("could not find volume '%v' in Deployment Config '%v'", volumeName, dc.Name)
+ err = removeVolumeFromDC(volumeName, dc)
+ if err != nil {
+ return err
}
klog.V(4).Infof("Found volume: %v in Deployment Config: %v", volumeName, dc.Name)
// Remove at max 2 volume mounts if volume mounts exists
- if !removeVolumeMountsFromDC(volumeName, dc) {
- return fmt.Errorf("could not find volumeMount: %v in Deployment Config: %v", volumeName, dc)
+ err = removeVolumeMountsFromDC(volumeName, dc)
+ if err != nil {
+ return err
}
_, updateErr := c.appsClient.DeploymentConfigs(c.Namespace).Update(dc)
diff --git a/pkg/occlient/volumes.go b/pkg/occlient/volumes.go
index 47e429bc6de..047a006c442 100644
--- a/pkg/occlient/volumes.go
+++ b/pkg/occlient/volumes.go
@@ -120,31 +120,86 @@ func (c *Client) getVolumeNamesFromPVC(pvc string, dc *appsv1.DeploymentConfig)
// removeVolumeFromDC removes the volume from the given Deployment Config and
// returns true. If the given volume is not found, it returns false.
-func removeVolumeFromDC(vol string, dc *appsv1.DeploymentConfig) bool {
+func removeVolumeFromDC(vol string, dc *appsv1.DeploymentConfig) error {
+
+ // Error out immediately if there are zero volumes to begin with
+ if len(dc.Spec.Template.Spec.Volumes) == 0 {
+ return errors.New("there are *no* volumes in this DeploymentConfig to remove")
+ }
+
found := false
- for i, volume := range dc.Spec.Template.Spec.Volumes {
- if volume.Name == vol {
- found = true
- dc.Spec.Template.Spec.Volumes = append(dc.Spec.Template.Spec.Volumes[:i], dc.Spec.Template.Spec.Volumes[i+1:]...)
+
+ // If for some reason there is only one volume, let's slice the array to zero length
+ // or else you will get a "runtime error: slice bounds of of range [2:1] error
+ if len(dc.Spec.Template.Spec.Volumes) == 1 && vol == dc.Spec.Template.Spec.Volumes[0].Name {
+ // Mark as found and slice to zero length
+ found = true
+ dc.Spec.Template.Spec.Volumes = dc.Spec.Template.Spec.Volumes[:0]
+ } else {
+
+ for i, volume := range dc.Spec.Template.Spec.Volumes {
+
+ // If we find a match
+ if volume.Name == vol {
+ found = true
+
+ // Copy (it takes longer, but maintains volume order)
+ copy(dc.Spec.Template.Spec.Volumes[i:], dc.Spec.Template.Spec.Volumes[i+1:])
+ dc.Spec.Template.Spec.Volumes = dc.Spec.Template.Spec.Volumes[:len(dc.Spec.Template.Spec.Volumes)-1]
+
+ break
+ }
+
}
}
- return found
+
+ if found {
+ return nil
+ }
+
+ return fmt.Errorf("unable to find volume '%s' within DeploymentConfig '%s'", vol, dc.ObjectMeta.Name)
}
// removeVolumeMountsFromDC removes the volumeMounts from all the given containers
// in the given Deployment Config and return true. If any of the volumeMount with the name
// is not found, it returns false.
-func removeVolumeMountsFromDC(vm string, dc *appsv1.DeploymentConfig) bool {
+func removeVolumeMountsFromDC(volumeMount string, dc *appsv1.DeploymentConfig) error {
+
+ if len(dc.Spec.Template.Spec.Containers) == 0 {
+ return errors.New("something went wrong, there are *no* containers available to iterate through")
+ }
+
found := false
+
for i, container := range dc.Spec.Template.Spec.Containers {
- for j, volumeMount := range container.VolumeMounts {
- if volumeMount.Name == vm {
- found = true
- dc.Spec.Template.Spec.Containers[i].VolumeMounts = append(dc.Spec.Template.Spec.Containers[i].VolumeMounts[:j], dc.Spec.Template.Spec.Containers[i].VolumeMounts[j+1:]...)
+
+ if len(dc.Spec.Template.Spec.Containers[i].VolumeMounts) == 1 && dc.Spec.Template.Spec.Containers[i].VolumeMounts[0].Name == volumeMount {
+ // Mark as found and slice to zero length
+ found = true
+ dc.Spec.Template.Spec.Containers[i].VolumeMounts = dc.Spec.Template.Spec.Containers[i].VolumeMounts[:0]
+ } else {
+
+ for j, volMount := range container.VolumeMounts {
+
+ // If we find a match
+ if volMount.Name == volumeMount {
+ found = true
+
+ // Copy (it takes longer, but maintains volume mount order)
+ copy(dc.Spec.Template.Spec.Containers[i].VolumeMounts[j:], dc.Spec.Template.Spec.Containers[i].VolumeMounts[j+1:])
+ dc.Spec.Template.Spec.Containers[i].VolumeMounts = dc.Spec.Template.Spec.Containers[i].VolumeMounts[:len(dc.Spec.Template.Spec.Containers[i].VolumeMounts)-1]
+
+ break
+ }
}
}
}
- return found
+
+ if found {
+ return nil
+ }
+
+ return fmt.Errorf("unable to find volume mount '%s'", volumeMount)
}
// generateVolumeNameFromPVC generates a random volume name based on the name
diff --git a/pkg/occlient/volumes_test.go b/pkg/occlient/volumes_test.go
index 16eee986f87..4ba354b393f 100644
--- a/pkg/occlient/volumes_test.go
+++ b/pkg/occlient/volumes_test.go
@@ -307,3 +307,107 @@ func Test_updateStorageOwnerReference(t *testing.T) {
})
}
}
+
+func TestRemoveVolumeFromDC(t *testing.T) {
+ type args struct {
+ volName string
+ dc appsv1.DeploymentConfig
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr bool
+ }{
+ {
+ name: "Case 1 - Test removing volumes",
+ args: args{
+ volName: "foo-s2idata",
+ dc: *fakeDeploymentConfig("foo", "bar", nil, nil, t),
+ },
+ wantErr: false,
+ },
+ {
+ name: "Case 2 - Error out, test removing non-existant volume",
+ args: args{
+ volName: "doesnotexist",
+ dc: *fakeDeploymentConfig("foo", "bar", nil, nil, t),
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+
+ err := removeVolumeFromDC(tt.args.volName, &tt.args.dc)
+
+ if tt.wantErr && err == nil {
+ t.Errorf("Wanted an error, got a pass")
+ }
+
+ if err != nil && !tt.wantErr {
+ t.Errorf("Got error: %s", err)
+ }
+
+ // Check that it was actually removed
+ for _, j := range tt.args.dc.Spec.Template.Spec.Volumes {
+ if j.Name == tt.args.volName {
+ t.Errorf("volume %s still exists even after removeVolumeFromDC function, %+v", tt.args.volName, tt.args.dc.Spec.Template.Spec.Containers)
+ }
+ }
+
+ })
+ }
+}
+
+func TestRemoveVolumeMountsFromDC(t *testing.T) {
+ type args struct {
+ volName string
+ dc appsv1.DeploymentConfig
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr bool
+ }{
+ {
+ name: "Case 1 - Test removing volume mount",
+ args: args{
+ volName: "foo-s2idata",
+ dc: *fakeDeploymentConfig("foo", "bar", nil, nil, t),
+ },
+ wantErr: false,
+ },
+ {
+ name: "Case 2 - Error out, test removing non-existant volume mount",
+ args: args{
+ volName: "doesnotexist",
+ dc: *fakeDeploymentConfig("foo", "bar", nil, nil, t),
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+
+ err := removeVolumeMountsFromDC(tt.args.volName, &tt.args.dc)
+
+ if tt.wantErr && err == nil {
+ t.Errorf("Wanted an error, got a pass")
+ }
+
+ if err != nil && !tt.wantErr {
+ t.Errorf("Got error: %s", err)
+ }
+
+ // Check that it was actually removed
+ for _, container := range tt.args.dc.Spec.Template.Spec.Containers {
+ for _, volMount := range container.VolumeMounts {
+ if volMount.Name == tt.args.volName {
+ t.Errorf("volume mount %s still exists even after removeVolumeMountsFromDC function, %+v", tt.args.volName, tt.args.dc.Spec.Template.Spec.Containers)
+ }
+ }
+ }
+
+ })
+ }
+}
diff --git a/pkg/odo/cli/catalog/list/components.go b/pkg/odo/cli/catalog/list/components.go
index db757f52ece..78e10fc8a02 100644
--- a/pkg/odo/cli/catalog/list/components.go
+++ b/pkg/odo/cli/catalog/list/components.go
@@ -57,10 +57,14 @@ func (o *ListComponentsOptions) Complete(name string, cmd *cobra.Command, args [
}
if experimental.IsExperimentalModeEnabled() {
- o.catalogDevfileList, err = catalog.ListDevfileComponents()
+ o.catalogDevfileList, err = catalog.ListDevfileComponents("")
if err != nil {
return err
}
+
+ if o.catalogDevfileList.DevfileRegistries == nil {
+ log.Warning("Please run 'odo registry add ' to add registry for listing devfile components\n")
+ }
}
return
@@ -130,7 +134,7 @@ func (o *ListComponentsOptions) Run() (err error) {
if len(supDevfileCatalogList) != 0 || (o.listAllDevfileComponents && len(unsupDevfileCatalogList) != 0) {
fmt.Fprintln(w, "Odo Devfile Components:")
- fmt.Fprintln(w, "NAME", "\t", "DESCRIPTION", "\t", "SUPPORTED")
+ fmt.Fprintln(w, "NAME", "\t", "DESCRIPTION", "\t", "REGISTRY", "\t", "SUPPORTED")
if len(supDevfileCatalogList) != 0 {
supported = "YES"
@@ -192,6 +196,6 @@ func (o *ListComponentsOptions) printCatalogList(w io.Writer, catalogList []cata
func (o *ListComponentsOptions) printDevfileCatalogList(w io.Writer, catalogDevfileList []catalog.DevfileComponentType, supported string) {
for _, devfileComponent := range catalogDevfileList {
- fmt.Fprintln(w, devfileComponent.Name, "\t", devfileComponent.Description, "\t", supported)
+ fmt.Fprintln(w, devfileComponent.Name, "\t", devfileComponent.Description, "\t", devfileComponent.Registry.Name, "\t", supported)
}
}
diff --git a/pkg/odo/cli/catalog/util/util_test.go b/pkg/odo/cli/catalog/util/util_test.go
index bc13ca6c977..fb24cc0ddce 100644
--- a/pkg/odo/cli/catalog/util/util_test.go
+++ b/pkg/odo/cli/catalog/util/util_test.go
@@ -29,7 +29,7 @@ func TestFilterHiddenServices(t *testing.T) {
input: catalog.ServiceTypeList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foobar",
@@ -72,7 +72,7 @@ func TestFilterHiddenServices(t *testing.T) {
expected: catalog.ServiceTypeList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foobar",
diff --git a/pkg/odo/cli/cli.go b/pkg/odo/cli/cli.go
index 6c0876f113f..a9c898acdff 100644
--- a/pkg/odo/cli/cli.go
+++ b/pkg/odo/cli/cli.go
@@ -16,6 +16,7 @@ import (
"github.com/openshift/odo/pkg/odo/cli/plugins"
"github.com/openshift/odo/pkg/odo/cli/preference"
"github.com/openshift/odo/pkg/odo/cli/project"
+ "github.com/openshift/odo/pkg/odo/cli/registry"
"github.com/openshift/odo/pkg/odo/cli/service"
"github.com/openshift/odo/pkg/odo/cli/storage"
"github.com/openshift/odo/pkg/odo/cli/url"
@@ -23,6 +24,7 @@ import (
"github.com/openshift/odo/pkg/odo/cli/version"
"github.com/openshift/odo/pkg/odo/util"
odoutil "github.com/openshift/odo/pkg/odo/util"
+ "github.com/openshift/odo/pkg/odo/util/experimental"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -145,7 +147,7 @@ func odoRootCmd(name, fullName string) *cobra.Command {
// We use "flag" in order to make this accessible throughtout ALL of odo, rather than the
// above traditional "persistentflags" usage that does not make it a pointer within the 'pflag'
// package
- flag.CommandLine.String("o", "json", "Specify output format, supported format: json")
+ flag.CommandLine.String("o", "", "Specify output format, supported format: json")
// Here we add the necessary "logging" flags.. However, we choose to hide some of these from the user
// as they are not necessarily needed and more for advanced debugging
@@ -197,6 +199,12 @@ func odoRootCmd(name, fullName string) *cobra.Command {
debug.NewCmdDebug(debug.RecommendedCommandName, util.GetFullName(fullName, debug.RecommendedCommandName)),
)
+ if experimental.IsExperimentalModeEnabled() {
+ rootCmd.AddCommand(
+ registry.NewCmdRegistry(registry.RecommendedCommandName, util.GetFullName(fullName, registry.RecommendedCommandName)),
+ )
+ }
+
odoutil.VisitCommands(rootCmd, reconfigureCmdWithSubcmd)
return rootCmd
diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go
index 2f8672a2583..02c2863041c 100644
--- a/pkg/odo/cli/component/create.go
+++ b/pkg/odo/cli/component/create.go
@@ -63,7 +63,7 @@ type DevfileMetadata struct {
componentNamespace string
devfileSupport bool
devfileLink string
- devfileRegistry string
+ devfileRegistry catalog.Registry
downloadSource bool
}
@@ -329,10 +329,13 @@ func (co *CreateOptions) Complete(name string, cmd *cobra.Command, args []string
co.CommonPushOptions.componentContext = co.componentContext
}
- catalogDevfileList, err := catalog.ListDevfileComponents()
+ catalogDevfileList, err := catalog.ListDevfileComponents(co.devfileMetadata.devfileRegistry.Name)
if err != nil {
return err
}
+ if catalogDevfileList.DevfileRegistries == nil {
+ log.Warning("Please run `odo registry add ` to add a registry then create a devfile components\n")
+ }
var componentType string
var componentName string
@@ -437,6 +440,8 @@ func (co *CreateOptions) Complete(name string, cmd *cobra.Command, args []string
}
}
+ registrySpinner := log.Spinnerf("Creating a devfile component from registry: %s", co.devfileMetadata.devfileRegistry.Name)
+
if co.devfileMetadata.devfileSupport {
err = co.InitEnvInfoFromContext()
if err != nil {
@@ -444,11 +449,13 @@ func (co *CreateOptions) Complete(name string, cmd *cobra.Command, args []string
}
spinner.End(true)
+ registrySpinner.End(true)
return nil
}
spinner.End(false)
- log.Italic("\nPlease run 'odo catalog list components' for a list of supported devfile component types")
+ registrySpinner.End(false)
+ log.Italic("\nPlease run `odo catalog list components` for a list of supported devfile component types")
}
if len(args) == 0 || !cmd.HasFlags() {
@@ -773,7 +780,7 @@ func (co *CreateOptions) Run() (err error) {
// Download devfile.yaml file and create env.yaml file
if co.devfileMetadata.devfileSupport {
if !util.CheckPathExists(DevfilePath) {
- err := util.DownloadFile(co.devfileMetadata.devfileRegistry+co.devfileMetadata.devfileLink, DevfilePath)
+ err := util.DownloadFile(co.devfileMetadata.devfileRegistry.URL+co.devfileMetadata.devfileLink, DevfilePath)
if err != nil {
return errors.Wrap(err, "Faile to download devfile.yaml for devfile component")
}
@@ -899,6 +906,7 @@ func NewCmdCreate(name, fullName string) *cobra.Command {
componentCreateCmd.Flags().StringSliceVar(&co.componentEnvVars, "env", []string{}, "Environmental variables for the component. For example --env VariableName=Value")
if experimental.IsExperimentalModeEnabled() {
+ componentCreateCmd.Flags().StringVar(&co.devfileMetadata.devfileRegistry.Name, "registry", "", "Create devfile component from specific registry")
componentCreateCmd.Flags().BoolVar(&co.devfileMetadata.downloadSource, "downloadSource", false, "Download sample project from devfile. (ex. odo component create [component_name] --downloadSource")
}
diff --git a/pkg/odo/cli/component/devfile.go b/pkg/odo/cli/component/devfile.go
index e2242bea7eb..1a7c13004b2 100644
--- a/pkg/odo/cli/component/devfile.go
+++ b/pkg/odo/cli/component/devfile.go
@@ -3,7 +3,6 @@ package component
import (
"fmt"
"os"
- "path/filepath"
"strings"
"github.com/openshift/odo/pkg/envinfo"
@@ -41,13 +40,13 @@ func (po *PushOptions) DevfilePush() (err error) {
return err
}
- componentName, err := getComponentName()
+ componentName, err := getComponentName(po.componentContext)
if err != nil {
return errors.Wrap(err, "unable to get component name")
}
// Set the source path to either the context or current working directory (if context not set)
- po.sourcePath, err = util.GetAbsPath(filepath.Dir(po.componentContext))
+ po.sourcePath, err = util.GetAbsPath(po.componentContext)
if err != nil {
return errors.Wrap(err, "unable to get source path")
}
@@ -68,7 +67,7 @@ func (po *PushOptions) DevfilePush() (err error) {
platformContext = kc
}
- devfileHandler, err := adapters.NewPlatformAdapter(componentName, devObj, platformContext)
+ devfileHandler, err := adapters.NewPlatformAdapter(componentName, po.componentContext, devObj, platformContext)
if err != nil {
return err
@@ -103,12 +102,18 @@ func (po *PushOptions) DevfilePush() (err error) {
}
// Get component name from env.yaml file
-func getComponentName() (string, error) {
- // Todo: Use context to get the approraite envinfo after context is supported in experimental mode
- dir, err := os.Getwd()
- if err != nil {
- return "", err
+func getComponentName(context string) (string, error) {
+ var dir string
+ var err error
+ if context == "" {
+ dir, err = os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ } else {
+ dir = context
}
+
envInfo, err := envinfo.NewEnvSpecificInfo(dir)
if err != nil {
return "", err
@@ -125,7 +130,7 @@ func (do *DeleteOptions) DevfileComponentDelete() error {
return err
}
- componentName, err := getComponentName()
+ componentName, err := getComponentName(do.componentContext)
if err != nil {
return err
}
@@ -137,7 +142,7 @@ func (do *DeleteOptions) DevfileComponentDelete() error {
labels := map[string]string{
"component": componentName,
}
- devfileHandler, err := adapters.NewPlatformAdapter(componentName, devObj, kc)
+ devfileHandler, err := adapters.NewPlatformAdapter(componentName, do.componentContext, devObj, kc)
if err != nil {
return err
}
diff --git a/pkg/odo/cli/component/push.go b/pkg/odo/cli/component/push.go
index 410ce31b11d..fee67195adc 100644
--- a/pkg/odo/cli/component/push.go
+++ b/pkg/odo/cli/component/push.go
@@ -2,6 +2,7 @@ package component
import (
"fmt"
+ "path/filepath"
"github.com/openshift/odo/pkg/envinfo"
"github.com/openshift/odo/pkg/odo/util/pushtarget"
@@ -58,6 +59,7 @@ func NewPushOptions() *PushOptions {
// Complete completes push args
func (po *PushOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) {
+ po.DevfilePath = filepath.Join(po.componentContext, po.DevfilePath)
// if experimental mode is enabled and devfile is present
if experimental.IsExperimentalModeEnabled() && util.CheckPathExists(po.DevfilePath) {
@@ -72,6 +74,7 @@ func (po *PushOptions) Complete(name string, cmd *cobra.Command, args []string)
// The namespace was retrieved from the --project flag (or from the kube client if not set) and stored in kclient when initalizing the context
po.namespace = po.KClient.Namespace
}
+
return nil
}
diff --git a/pkg/odo/cli/component/watch.go b/pkg/odo/cli/component/watch.go
index fbe2d7c522d..3eacffac71c 100644
--- a/pkg/odo/cli/component/watch.go
+++ b/pkg/odo/cli/component/watch.go
@@ -72,6 +72,8 @@ func NewWatchOptions() *WatchOptions {
// Complete completes watch args
func (wo *WatchOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) {
+ wo.devfilePath = filepath.Join(wo.componentContext, wo.devfilePath)
+
// if experimental mode is enabled and devfile is present
if experimental.IsExperimentalModeEnabled() && util.CheckPathExists(wo.devfilePath) {
envinfo, err := envinfo.NewEnvSpecificInfo(wo.componentContext)
@@ -82,7 +84,7 @@ func (wo *WatchOptions) Complete(name string, cmd *cobra.Command, args []string)
wo.Context = genericclioptions.NewDevfileContext(cmd)
// Set the source path to either the context or current working directory (if context not set)
- wo.sourcePath, err = util.GetAbsPath(filepath.Dir(wo.componentContext))
+ wo.sourcePath, err = util.GetAbsPath(wo.componentContext)
if err != nil {
return errors.Wrap(err, "unable to get source path")
}
@@ -94,7 +96,7 @@ func (wo *WatchOptions) Complete(name string, cmd *cobra.Command, args []string)
}
// Get the component name
- wo.componentName, err = getComponentName()
+ wo.componentName, err = getComponentName(wo.componentContext)
if err != nil {
return err
}
@@ -115,7 +117,7 @@ func (wo *WatchOptions) Complete(name string, cmd *cobra.Command, args []string)
} else {
platformContext = nil
}
- wo.devfileHandler, err = adapters.NewPlatformAdapter(wo.componentName, devObj, platformContext)
+ wo.devfileHandler, err = adapters.NewPlatformAdapter(wo.componentName, wo.componentContext, devObj, platformContext)
return err
}
diff --git a/pkg/odo/cli/registry/add.go b/pkg/odo/cli/registry/add.go
new file mode 100644
index 00000000000..ca891b3c391
--- /dev/null
+++ b/pkg/odo/cli/registry/add.go
@@ -0,0 +1,95 @@
+package registry
+
+import (
+ // Built-in packages
+ "fmt"
+
+ // Third-party packages
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ ktemplates "k8s.io/kubectl/pkg/util/templates"
+
+ // odo packages
+ "github.com/openshift/odo/pkg/log"
+ "github.com/openshift/odo/pkg/odo/genericclioptions"
+ "github.com/openshift/odo/pkg/preference"
+ "github.com/openshift/odo/pkg/util"
+)
+
+const addCommandName = "add"
+
+// "odo registry add" command description and examples
+var (
+ addLongDesc = ktemplates.LongDesc(`Add devfile registry`)
+
+ addExample = ktemplates.Examples(`# Add devfile registry
+ %[1]s CheRegistry https://che-devfile-registry.openshift.io
+
+ %[1]s CheRegistryFromGitHub https://raw.githubusercontent.com/eclipse/che-devfile-registry/master
+ `)
+)
+
+// AddOptions encapsulates the options for the "odo registry add" command
+type AddOptions struct {
+ operation string
+ registryName string
+ registryURL string
+ forceFlag bool
+}
+
+// NewAddOptions creates a new AddOptions instance
+func NewAddOptions() *AddOptions {
+ return &AddOptions{}
+}
+
+// Complete completes AddOptions after they've been created
+func (o *AddOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) {
+ o.operation = "add"
+ o.registryName = args[0]
+ o.registryURL = args[1]
+ return
+}
+
+// Validate validates the AddOptions based on completed values
+func (o *AddOptions) Validate() (err error) {
+ err = util.ValidateURL(o.registryURL)
+ if err != nil {
+ return err
+ }
+
+ return
+}
+
+// Run contains the logic for "odo registry add" command
+func (o *AddOptions) Run() (err error) {
+
+ cfg, err := preference.New()
+ if err != nil {
+ return errors.Wrap(err, "unable to add registry")
+ }
+
+ err = cfg.RegistryHandler(o.operation, o.registryName, o.registryURL, o.forceFlag)
+ if err != nil {
+ return err
+ }
+
+ log.Info("New registry successfully added")
+ return nil
+}
+
+// NewCmdAdd implements the "odo registry add" command
+func NewCmdAdd(name, fullName string) *cobra.Command {
+ o := NewAddOptions()
+ registryAddCmd := &cobra.Command{
+ Use: fmt.Sprintf("%s ", name),
+ Short: addLongDesc,
+ Long: addLongDesc,
+ Example: fmt.Sprintf(fmt.Sprint(addExample), fullName),
+ Args: cobra.ExactArgs(2),
+ Run: func(cmd *cobra.Command, args []string) {
+ genericclioptions.GenericRun(o, cmd, args)
+ },
+ }
+
+ return registryAddCmd
+}
diff --git a/pkg/odo/cli/registry/delete.go b/pkg/odo/cli/registry/delete.go
new file mode 100644
index 00000000000..4d3ea5c00f6
--- /dev/null
+++ b/pkg/odo/cli/registry/delete.go
@@ -0,0 +1,86 @@
+package registry
+
+import (
+ // Built-in packages
+ "fmt"
+
+ // Third-party packages
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ ktemplates "k8s.io/kubectl/pkg/util/templates"
+
+ // odo packages
+ "github.com/openshift/odo/pkg/odo/genericclioptions"
+ "github.com/openshift/odo/pkg/preference"
+)
+
+const deleteCommandName = "delete"
+
+// "odo registry delete" command description and examples
+var (
+ deleteLongDesc = ktemplates.LongDesc(`Delete devfile registry`)
+
+ deleteExample = ktemplates.Examples(`# Delete devfile registry
+ %[1]s CheRegistry
+ `)
+)
+
+// DeleteOptions encapsulates the options for the "odo registry delete" command
+type DeleteOptions struct {
+ operation string
+ registryName string
+ registryURL string
+ forceFlag bool
+}
+
+// NewDeleteOptions creates a new DeleteOptions instance
+func NewDeleteOptions() *DeleteOptions {
+ return &DeleteOptions{}
+}
+
+// Complete completes DeleteOptions after they've been created
+func (o *DeleteOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) {
+ o.operation = "delete"
+ o.registryName = args[0]
+ o.registryURL = ""
+ return
+}
+
+// Validate validates the DeleteOptions based on completed values
+func (o *DeleteOptions) Validate() (err error) {
+ return
+}
+
+// Run contains the logic for "odo registry delete" command
+func (o *DeleteOptions) Run() (err error) {
+ cfg, err := preference.New()
+ if err != nil {
+ return errors.Wrap(err, "unable to delete registry")
+ }
+
+ err = cfg.RegistryHandler(o.operation, o.registryName, o.registryURL, o.forceFlag)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// NewCmdDelete implements the "odo registry delete" command
+func NewCmdDelete(name, fullName string) *cobra.Command {
+ o := NewDeleteOptions()
+ registryDeleteCmd := &cobra.Command{
+ Use: fmt.Sprintf("%s ", name),
+ Short: deleteLongDesc,
+ Long: deleteLongDesc,
+ Example: fmt.Sprintf(fmt.Sprint(deleteExample), fullName),
+ Args: cobra.ExactArgs(1),
+ Run: func(cmd *cobra.Command, args []string) {
+ genericclioptions.GenericRun(o, cmd, args)
+ },
+ }
+
+ registryDeleteCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Don't ask for confirmation, delete the registry directly")
+
+ return registryDeleteCmd
+}
diff --git a/pkg/odo/cli/registry/list.go b/pkg/odo/cli/registry/list.go
new file mode 100644
index 00000000000..dac98ba7414
--- /dev/null
+++ b/pkg/odo/cli/registry/list.go
@@ -0,0 +1,88 @@
+package registry
+
+import (
+ // Built-in packages
+ "fmt"
+ "io"
+ "os"
+ "text/tabwriter"
+
+ // Third-party packages
+ "github.com/spf13/cobra"
+ ktemplates "k8s.io/kubectl/pkg/util/templates"
+
+ // odo packages
+ "github.com/openshift/odo/pkg/odo/genericclioptions"
+ "github.com/openshift/odo/pkg/odo/util"
+ "github.com/openshift/odo/pkg/preference"
+)
+
+const listCommandName = "list"
+
+// "odo registry list" command description and examples
+var (
+ listDesc = ktemplates.LongDesc(`List devfile registry`)
+
+ listExample = ktemplates.Examples(`# List devfile registry
+ %[1]s
+ `)
+)
+
+// ListOptions encapsulates the options for "odo registry list" command
+type ListOptions struct {
+}
+
+// NewListOptions creates a new ListOptions instance
+func NewListOptions() *ListOptions {
+ return &ListOptions{}
+}
+
+// Complete completes ListOptions after they've been created
+func (o *ListOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) {
+ return
+}
+
+// Validate validates the ListOptions based on completed values
+func (o *ListOptions) Validate() (err error) {
+ return
+}
+
+// Run contains the logic for "odo registry list" command
+func (o *ListOptions) Run() (err error) {
+ cfg, err := preference.New()
+ if err != nil {
+ util.LogErrorAndExit(err, "")
+ }
+
+ w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
+ fmt.Fprintln(w, "NAME", "\t", "URL")
+ o.printRegistryList(w, cfg.OdoSettings.RegistryList)
+ w.Flush()
+ return
+}
+
+func (o *ListOptions) printRegistryList(w io.Writer, registryList *[]preference.Registry) {
+ if registryList == nil {
+ return
+ }
+
+ for _, registry := range *registryList {
+ fmt.Fprintln(w, registry.Name, "\t", registry.URL)
+ }
+}
+
+// NewCmdList implements the "odo registry list" command
+func NewCmdList(name, fullName string) *cobra.Command {
+ o := NewListOptions()
+ registryListCmd := &cobra.Command{
+ Use: name,
+ Short: listDesc,
+ Long: listDesc,
+ Example: fmt.Sprintf(fmt.Sprint(listExample), fullName),
+ Args: cobra.ExactArgs(0),
+ Run: func(cmd *cobra.Command, args []string) {
+ genericclioptions.GenericRun(o, cmd, args)
+ },
+ }
+ return registryListCmd
+}
diff --git a/pkg/odo/cli/registry/registry.go b/pkg/odo/cli/registry/registry.go
new file mode 100644
index 00000000000..a4c85bac9ff
--- /dev/null
+++ b/pkg/odo/cli/registry/registry.go
@@ -0,0 +1,44 @@
+package registry
+
+import (
+ // Built-in packages
+ "fmt"
+
+ // Third-party packages
+ "github.com/spf13/cobra"
+ ktemplates "k8s.io/kubectl/pkg/util/templates"
+
+ // odo packages
+ "github.com/openshift/odo/pkg/odo/util"
+)
+
+// RecommendedCommandName is the recommended registry command name
+const RecommendedCommandName = "registry"
+
+var registryDesc = ktemplates.LongDesc(`Configure devfile registry`)
+
+// NewCmdRegistry implements the registry configuration command
+func NewCmdRegistry(name, fullName string) *cobra.Command {
+ registryAddCmd := NewCmdAdd(addCommandName, util.GetFullName(fullName, addCommandName))
+ registryListCmd := NewCmdList(listCommandName, util.GetFullName(fullName, listCommandName))
+ registryUpdateCmd := NewCmdUpdate(updateCommandName, util.GetFullName(fullName, updateCommandName))
+ registryDeleteCmd := NewCmdDelete(deleteCommandName, util.GetFullName(fullName, deleteCommandName))
+
+ registryCmd := &cobra.Command{
+ Use: name,
+ Short: registryDesc,
+ Long: registryDesc,
+ Example: fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s",
+ registryAddCmd.Example,
+ registryListCmd.Example,
+ registryUpdateCmd.Example,
+ registryDeleteCmd.Example,
+ ),
+ }
+
+ registryCmd.AddCommand(registryAddCmd, registryListCmd, registryUpdateCmd, registryDeleteCmd)
+ registryCmd.SetUsageTemplate(util.CmdUsageTemplate)
+ registryCmd.Annotations = map[string]string{"command": "main"}
+
+ return registryCmd
+}
diff --git a/pkg/odo/cli/registry/update.go b/pkg/odo/cli/registry/update.go
new file mode 100644
index 00000000000..afdab02de5a
--- /dev/null
+++ b/pkg/odo/cli/registry/update.go
@@ -0,0 +1,92 @@
+package registry
+
+import (
+ // Built-in packages
+ "fmt"
+
+ // Third-party packages
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ ktemplates "k8s.io/kubectl/pkg/util/templates"
+
+ // odo packages
+ "github.com/openshift/odo/pkg/odo/genericclioptions"
+ "github.com/openshift/odo/pkg/preference"
+ "github.com/openshift/odo/pkg/util"
+)
+
+const updateCommandName = "update"
+
+// "odo registry update" command description and examples
+var (
+ updateLongDesc = ktemplates.LongDesc(`Update devfile registry URL`)
+
+ updateExample = ktemplates.Examples(`# Update devfile registry URL
+ %[1]s CheRegistry https://che-devfile-registry-update.openshift.io
+ `)
+)
+
+// UpdateOptions encapsulates the options for the "odo registry update" command
+type UpdateOptions struct {
+ operation string
+ registryName string
+ registryURL string
+ forceFlag bool
+}
+
+// NewUpdateOptions creates a new UpdateOptions instance
+func NewUpdateOptions() *UpdateOptions {
+ return &UpdateOptions{}
+}
+
+// Complete completes UpdateOptions after they've been created
+func (o *UpdateOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) {
+ o.operation = "update"
+ o.registryName = args[0]
+ o.registryURL = args[1]
+ return
+}
+
+// Validate validates the UpdateOptions based on completed values
+func (o *UpdateOptions) Validate() (err error) {
+ err = util.ValidateURL(o.registryURL)
+ if err != nil {
+ return err
+ }
+
+ return
+}
+
+// Run contains the logic for "odo registry update" command
+func (o *UpdateOptions) Run() (err error) {
+ cfg, err := preference.New()
+ if err != nil {
+ return errors.Wrap(err, "unable to update registry")
+ }
+
+ err = cfg.RegistryHandler(o.operation, o.registryName, o.registryURL, o.forceFlag)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// NewCmdUpdate implements the "odo registry update" command
+func NewCmdUpdate(name, fullName string) *cobra.Command {
+ o := NewUpdateOptions()
+ registryUpdateCmd := &cobra.Command{
+ Use: fmt.Sprintf("%s ", name),
+ Short: updateLongDesc,
+ Long: updateLongDesc,
+ Example: fmt.Sprintf(fmt.Sprint(updateExample), fullName),
+ Args: cobra.ExactArgs(2),
+ Run: func(cmd *cobra.Command, args []string) {
+ genericclioptions.GenericRun(o, cmd, args)
+ },
+ }
+
+ registryUpdateCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Don't ask for confirmation, update the registry directly")
+
+ return registryUpdateCmd
+}
diff --git a/pkg/odo/genericclioptions/runnable.go b/pkg/odo/genericclioptions/runnable.go
index eb464fa029b..cab80b6fa38 100644
--- a/pkg/odo/genericclioptions/runnable.go
+++ b/pkg/odo/genericclioptions/runnable.go
@@ -94,5 +94,12 @@ func CheckMachineReadableOutputCommand(cmd *cobra.Command) {
// is not malformed / mixed in with normal logging
if log.IsJSON() {
_ = flag.Set("v", "0")
+ } else {
+ // Override the logging level by the value (if set) by the ODO_LOG_LEVEL env
+ // The "-v" flag set on command line will take precedence over ODO_LOG_LEVEL env
+ v := flag.CommandLine.Lookup("v").Value.String()
+ if level, ok := os.LookupEnv("ODO_LOG_LEVEL"); ok && v == "0" {
+ _ = flag.CommandLine.Set("v", level)
+ }
}
}
diff --git a/pkg/preference/preference.go b/pkg/preference/preference.go
index 460a7c0f447..5f6239ad1a5 100644
--- a/pkg/preference/preference.go
+++ b/pkg/preference/preference.go
@@ -12,6 +12,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
+ "github.com/openshift/odo/pkg/log"
+ "github.com/openshift/odo/pkg/odo/cli/ui"
"github.com/openshift/odo/pkg/util"
)
@@ -19,7 +21,7 @@ const (
GlobalConfigEnvName = "GLOBALODOCONFIG"
configFileName = "preference.yaml"
preferenceKind = "Preference"
- preferenceAPIVersion = "odo.openshift.io/v1alpha1"
+ preferenceAPIVersion = "odo.dev/v1alpha1"
//DefaultTimeout for openshift server connection check (in seconds)
DefaultTimeout = 1
@@ -64,6 +66,18 @@ const (
// KubePushTarget represents the value of the push target when it's set to Kube
KubePushTarget = "kube"
+
+ // CheDevfileRegistryName is the name of Che devfile registry
+ CheDevfileRegistryName = "CheDevfileRegistry"
+
+ // CheDevfileRegistryURL is the URL of Che devfile registry
+ CheDevfileRegistryURL = "https://che-devfile-registry.openshift.io"
+
+ // DefaultDevfileRegistryName is the name of default devfile registry
+ DefaultDevfileRegistryName = "DefaultDevfileRegistry"
+
+ // DefaultDevfileRegistryURL is the URL of default devfile registry
+ DefaultDevfileRegistryURL = "https://raw.githubusercontent.com/elsony/devfile-registry/master"
)
// TimeoutSettingDescription is human-readable description for the timeout setting
@@ -117,6 +131,15 @@ type OdoSettings struct {
// PushTarget for telling odo which platform to push to (either kube or docker)
PushTarget *string `yaml:"PushTarget,omitempty"`
+
+ // RegistryList for telling odo to connect to all the registries in the registry list
+ RegistryList *[]Registry `yaml:"RegistryList,omitempty"`
+}
+
+// Registry includes the registry metadata
+type Registry struct {
+ Name string `yaml:"Name,omitempty"`
+ URL string `yaml:"URL,omitempty"`
}
// Preference stores all the preferences related to odo
@@ -171,7 +194,8 @@ func NewPreferenceInfo() (*PreferenceInfo, error) {
Preference: NewPreference(),
Filename: preferenceFile,
}
- // if the preference file doesn't exist then we dont worry about it and return
+
+ // If the preference file doesn't exist then we return with default preference
if _, err = os.Stat(preferenceFile); os.IsNotExist(err) {
return &c, nil
}
@@ -180,9 +204,124 @@ func NewPreferenceInfo() (*PreferenceInfo, error) {
if err != nil {
return nil, err
}
+
+ if c.OdoSettings.Experimental != nil && *c.OdoSettings.Experimental {
+ if c.OdoSettings.RegistryList == nil {
+ // Handle user has preference file but doesn't use dynamic registry before
+ defaultRegistryList := []Registry{
+ {
+ Name: CheDevfileRegistryName,
+ URL: CheDevfileRegistryURL,
+ },
+ {
+ Name: DefaultDevfileRegistryName,
+ URL: DefaultDevfileRegistryURL,
+ },
+ }
+ c.OdoSettings.RegistryList = &defaultRegistryList
+ }
+ }
+
return &c, nil
}
+// RegistryHandler handles registry add, update and delete operations
+func (c *PreferenceInfo) RegistryHandler(operation string, registryName string, registryURL string, forceFlag bool) error {
+ var registryList []Registry
+ var err error
+ registryExist := false
+
+ // Registry list is empty
+ if c.OdoSettings.RegistryList == nil {
+ registryList, err = handleWithoutRegistryExist(registryList, operation, registryName, registryURL)
+ if err != nil {
+ return err
+ }
+ } else {
+ // The target registry exists in the registry list
+ registryList = *c.OdoSettings.RegistryList
+ for index, registry := range registryList {
+ if registry.Name == registryName {
+ registryExist = true
+ registryList, err = handleWithRegistryExist(index, registryList, operation, registryName, registryURL, forceFlag)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // The target registry doesn't exist in the registry list
+ if !registryExist {
+ registryList, err = handleWithoutRegistryExist(registryList, operation, registryName, registryURL)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ c.OdoSettings.RegistryList = ®istryList
+ err = util.WriteToFile(&c.Preference, c.Filename)
+ if err != nil {
+ return errors.Wrapf(err, "unable to write the configuration of %s operation to preference file", operation)
+ }
+
+ return nil
+}
+
+func handleWithoutRegistryExist(registryList []Registry, operation string, registryName string, registryURL string) ([]Registry, error) {
+ switch operation {
+
+ case "add":
+ registry := Registry{
+ Name: registryName,
+ URL: registryURL,
+ }
+ registryList = append(registryList, registry)
+
+ case "update":
+ return nil, errors.Errorf("failed to update registry: registry %s doesn't exist", registryName)
+
+ case "delete":
+ return nil, errors.Errorf("failed to delete registry: registry %s doesn't exist", registryName)
+ }
+
+ return registryList, nil
+}
+
+func handleWithRegistryExist(index int, registryList []Registry, operation string, registryName string, registryURL string, forceFlag bool) ([]Registry, error) {
+ switch operation {
+
+ case "add":
+ return nil, errors.Errorf("failed to add registry: registry %s already exists", registryName)
+
+ case "update":
+ if !forceFlag {
+ if !ui.Proceed(fmt.Sprintf("Are you sure you want to update registry %s", registryName)) {
+ log.Info("Aborted by the user")
+ return registryList, nil
+ }
+ }
+
+ registryList[index].URL = registryURL
+ log.Info("Successfully updated registry")
+
+ case "delete":
+ if !forceFlag {
+ if !ui.Proceed(fmt.Sprintf("Are you sure you want to delete registry %s", registryName)) {
+ log.Info("Aborted by the user")
+ return registryList, nil
+ }
+ }
+
+ copy(registryList[index:], registryList[index+1:])
+ registryList[len(registryList)-1] = Registry{}
+ registryList = registryList[:len(registryList)-1]
+ log.Info("Successfully deleted registry")
+ }
+
+ return registryList, nil
+}
+
// SetConfiguration modifies Odo configurations in the config file
// as of now being used for nameprefix, timeout, updatenotification
// TODO: Use reflect to set parameters
diff --git a/pkg/preference/preference_test.go b/pkg/preference/preference_test.go
index 73c202c0fb4..d3b5ea22407 100644
--- a/pkg/preference/preference_test.go
+++ b/pkg/preference/preference_test.go
@@ -703,3 +703,132 @@ func TestMetaTypePopulatedInPreference(t *testing.T) {
t.Error("the api version and kind in preference are incorrect")
}
}
+
+func TestHandleWithoutRegistryExist(t *testing.T) {
+ tests := []struct {
+ name string
+ registryList []Registry
+ operation string
+ registryName string
+ registryURL string
+ want []Registry
+ }{
+ {
+ name: "Case 1: Add registry",
+ registryList: []Registry{},
+ operation: "add",
+ registryName: "testName",
+ registryURL: "testURL",
+ want: []Registry{
+ {
+ Name: "testName",
+ URL: "testURL",
+ },
+ },
+ },
+ {
+ name: "Case 2: Update registry",
+ registryList: []Registry{},
+ operation: "update",
+ registryName: "testName",
+ registryURL: "testURL",
+ want: nil,
+ },
+ {
+ name: "Case 3: Delete registry",
+ registryList: []Registry{},
+ operation: "delete",
+ registryName: "testName",
+ registryURL: "testURL",
+ want: nil,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := handleWithoutRegistryExist(tt.registryList, tt.operation, tt.registryName, tt.registryURL)
+ if err != nil {
+ t.Logf("Error message is %v", err)
+ }
+
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("Got: %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestHandleWithRegistryExist(t *testing.T) {
+ tests := []struct {
+ name string
+ index int
+ registryList []Registry
+ operation string
+ registryName string
+ registryURL string
+ forceFlag bool
+ want []Registry
+ }{
+ {
+ name: "Case 1: Add registry",
+ index: 0,
+ registryList: []Registry{
+ {
+ Name: "testName",
+ URL: "testURL",
+ },
+ },
+ operation: "add",
+ registryName: "testName",
+ registryURL: "addURL",
+ forceFlag: false,
+ want: nil,
+ },
+ {
+ name: "Case 2: update registry",
+ index: 0,
+ registryList: []Registry{
+ {
+ Name: "testName",
+ URL: "testURL",
+ },
+ },
+ operation: "update",
+ registryName: "testName",
+ registryURL: "updateURL",
+ forceFlag: true,
+ want: []Registry{
+ {
+ Name: "testName",
+ URL: "updateURL",
+ },
+ },
+ },
+ {
+ name: "Case 3: Delete registry",
+ index: 0,
+ registryList: []Registry{
+ {
+ Name: "testName",
+ URL: "testURL",
+ },
+ },
+ operation: "delete",
+ registryName: "testName",
+ registryURL: "",
+ forceFlag: true,
+ want: []Registry{},
+ },
+ }
+
+ for _, tt := range tests {
+ got, err := handleWithRegistryExist(tt.index, tt.registryList, tt.operation, tt.registryName, tt.registryURL, tt.forceFlag)
+ if err != nil {
+ t.Logf("Error message is %v", err)
+ }
+
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("Got: %v, want: %v", got, tt.want)
+ }
+ }
+}
diff --git a/pkg/project/project.go b/pkg/project/project.go
index a51d0467c4b..a12a740563e 100644
--- a/pkg/project/project.go
+++ b/pkg/project/project.go
@@ -10,6 +10,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
+const apiVersion = "odo.dev/v1alpha1"
+
// GetCurrent return current project
func GetCurrent(client *occlient.Client) string {
project := client.GetCurrentProjectName()
@@ -98,7 +100,7 @@ func GetMachineReadableFormat(projectName string, isActive bool) Project {
return Project{
TypeMeta: metav1.TypeMeta{
Kind: "Project",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: projectName,
@@ -117,7 +119,7 @@ func MachineReadableSuccessOutput(projectName string, message string) {
machineOutput := machineoutput.GenericSuccess{
TypeMeta: metav1.TypeMeta{
Kind: "Project",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: projectName,
@@ -134,7 +136,7 @@ func getMachineReadableFormatForList(projects []Project) ProjectList {
return ProjectList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ListMeta: metav1.ListMeta{},
Items: projects,
diff --git a/pkg/service/service.go b/pkg/service/service.go
index 2e9806d6fd4..033d3ce4485 100644
--- a/pkg/service/service.go
+++ b/pkg/service/service.go
@@ -22,6 +22,7 @@ import (
const provisionedAndBoundStatus = "ProvisionedAndBound"
const provisionedAndLinkedStatus = "ProvisionedAndLinked"
+const apiVersion = "odo.dev/v1alpha1"
// NewServicePlanParameter creates a new ServicePlanParameter instance with the specified state
func NewServicePlanParameter(name, typeName, defaultValue string, required bool) ServicePlanParameter {
@@ -144,7 +145,7 @@ func List(client *occlient.Client, applicationName string) (ServiceList, error)
Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: elem.Labels[componentlabels.ComponentLabel],
@@ -157,7 +158,7 @@ func List(client *occlient.Client, applicationName string) (ServiceList, error)
return ServiceList{
TypeMeta: metav1.TypeMeta{
Kind: "ServiceList",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
Items: services,
}, nil
@@ -213,7 +214,7 @@ func ListWithDetailedStatus(client *occlient.Client, applicationName string) (Se
return ServiceList{
TypeMeta: metav1.TypeMeta{
Kind: "ServiceList",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
Items: services.Items,
}, nil
diff --git a/pkg/service/service_test.go b/pkg/service/service_test.go
index 83692762a12..6ffbc971448 100644
--- a/pkg/service/service_test.go
+++ b/pkg/service/service_test.go
@@ -3,6 +3,7 @@ package service
import (
"encoding/json"
"fmt"
+
"github.com/kylelemons/godebug/pretty"
"github.com/onsi/gomega/matchers"
"github.com/openshift/odo/pkg/testingutil"
@@ -390,10 +391,10 @@ func TestListWithDetailedStatus(t *testing.T) {
},
},
output: []Service{
- Service{
+ {
TypeMeta: metav1.TypeMeta{
Kind: "Service",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "mysql-persistent",
@@ -406,10 +407,10 @@ func TestListWithDetailedStatus(t *testing.T) {
Status: "ProvisionedAndLinked",
},
},
- Service{
+ {
TypeMeta: metav1.TypeMeta{
Kind: "Service",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "postgresql-ephemeral",
@@ -422,10 +423,10 @@ func TestListWithDetailedStatus(t *testing.T) {
Status: "ProvisionedAndBound",
},
},
- Service{
+ {
TypeMeta: metav1.TypeMeta{
Kind: "Service",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "mongodb",
@@ -438,10 +439,10 @@ func TestListWithDetailedStatus(t *testing.T) {
Status: "ProvisionedSuccessfully",
},
},
- Service{
+ {
TypeMeta: metav1.TypeMeta{
Kind: "Service",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "jenkins-persistent",
diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go
index e80c756b8bd..b2e05e35de7 100644
--- a/pkg/storage/storage.go
+++ b/pkg/storage/storage.go
@@ -18,6 +18,8 @@ import (
"k8s.io/klog"
)
+const apiVersion = "odo.dev/v1alpha1"
+
// Get returns Storage defination for given Storage name
func (storages StorageList) Get(storageName string) Storage {
for _, storage := range storages.Items {
@@ -442,7 +444,7 @@ func GetMachineReadableFormatForList(storage []Storage) StorageList {
return StorageList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ListMeta: metav1.ListMeta{},
Items: storage,
@@ -453,7 +455,7 @@ func GetMachineReadableFormatForList(storage []Storage) StorageList {
// storagePath indicates the path to which the storage is mounted to, "" if not mounted
func GetMachineReadableFormat(storageName, storageSize, storagePath string) Storage {
return Storage{
- TypeMeta: metav1.TypeMeta{Kind: "storage", APIVersion: "odo.openshift.io/v1alpha1"},
+ TypeMeta: metav1.TypeMeta{Kind: "storage", APIVersion: apiVersion},
ObjectMeta: metav1.ObjectMeta{Name: storageName},
Spec: StorageSpec{
Size: storageSize,
diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go
index 50a2cb32e60..75933fab689 100644
--- a/pkg/storage/storage_test.go
+++ b/pkg/storage/storage_test.go
@@ -89,7 +89,7 @@ func TestGetMachineReadableFormat(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: "pvc-example",
},
- TypeMeta: metav1.TypeMeta{Kind: "storage", APIVersion: "odo.openshift.io/v1alpha1"},
+ TypeMeta: metav1.TypeMeta{Kind: "storage", APIVersion: "odo.dev/v1alpha1"},
Spec: StorageSpec{
Size: "100Mi",
Path: "data",
@@ -106,7 +106,7 @@ func TestGetMachineReadableFormat(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: "pvc-example",
},
- TypeMeta: metav1.TypeMeta{Kind: "storage", APIVersion: "odo.openshift.io/v1alpha1"},
+ TypeMeta: metav1.TypeMeta{Kind: "storage", APIVersion: "odo.dev/v1alpha1"},
Spec: StorageSpec{
Size: "500Mi",
Path: "",
@@ -140,7 +140,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
},
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
Spec: StorageSpec{
Size: "100Mi",
@@ -151,7 +151,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
want: StorageList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ListMeta: metav1.ListMeta{},
Items: []Storage{
@@ -161,7 +161,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
},
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
Spec: StorageSpec{
Size: "100Mi",
@@ -180,7 +180,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
},
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
Spec: StorageSpec{
Size: "100Mi",
@@ -193,7 +193,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
},
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
Spec: StorageSpec{
Size: "500Mi",
@@ -204,7 +204,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
want: StorageList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
ListMeta: metav1.ListMeta{},
Items: []Storage{
@@ -214,7 +214,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
},
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
Spec: StorageSpec{
Size: "100Mi",
@@ -227,7 +227,7 @@ func TestGetMachineReadableFormatForList(t *testing.T) {
},
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: "odo.dev/v1alpha1",
},
Spec: StorageSpec{
Size: "500Mi",
diff --git a/pkg/url/url.go b/pkg/url/url.go
index a73b33b044a..300c027dde2 100644
--- a/pkg/url/url.go
+++ b/pkg/url/url.go
@@ -29,6 +29,8 @@ import (
"k8s.io/klog"
)
+const apiVersion = "odo.dev/v1alpha1"
+
// Get returns URL definition for given URL name
func (urls URLList) Get(urlName string) URL {
for _, url := range urls.Items {
@@ -383,7 +385,7 @@ func ConvertConfigURL(configURL config.ConfigURL) URL {
return URL{
TypeMeta: metav1.TypeMeta{
Kind: "url",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: configURL.Name,
@@ -485,7 +487,7 @@ func GetValidExposedPortNumber(exposedPort int) (int, error) {
// getMachineReadableFormat gives machine readable URL definition
func getMachineReadableFormat(r routev1.Route) URL {
return URL{
- TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.openshift.io/v1alpha1"},
+ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: apiVersion},
ObjectMeta: metav1.ObjectMeta{Name: r.Labels[urlLabels.URLLabel]},
Spec: URLSpec{Host: r.Spec.Host, Port: r.Spec.Port.TargetPort.IntValue(), Protocol: GetProtocol(r, iextensionsv1.Ingress{}, experimental.IsExperimentalModeEnabled()), Secure: r.Spec.TLS != nil},
}
@@ -496,7 +498,7 @@ func getMachineReadableFormatForList(urls []URL) URLList {
return URLList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "odo.openshift.io/v1alpha1",
+ APIVersion: apiVersion,
},
ListMeta: metav1.ListMeta{},
Items: urls,
@@ -516,7 +518,7 @@ func getMachineReadableFormatForIngressList(ingresses []iextensionsv1.Ingress) i
return iextensionsv1.IngressList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
- APIVersion: "udo.udo.io/v1alpha1",
+ APIVersion: apiVersion,
},
ListMeta: metav1.ListMeta{},
Items: ingresses,
@@ -575,6 +577,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam
for _, url := range urlList.Items {
urlCLUSTER[url.Name] = URL{
Spec: URLSpec{
+ Host: url.Spec.Rules[0].Host,
Port: int(url.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort.IntVal),
urlKind: envinfo.INGRESS,
},
@@ -603,7 +606,21 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam
// find URLs to delete
for urlName, urlSpec := range urlCLUSTER {
val, ok := urlLOCAL[urlName]
- if !ok {
+
+ configMismatch := false
+ if ok {
+ // since the host stored in an ingress
+ // is the combination of name and host of the url
+ if val.Spec.urlKind == envinfo.INGRESS {
+ val.Spec.Host = fmt.Sprintf("%v.%v", urlName, val.Spec.Host)
+ }
+ if !reflect.DeepEqual(val.Spec, urlSpec.Spec) {
+ configMismatch = true
+ klog.V(4).Infof("config and cluster mismatch for url %s", urlName)
+ }
+ }
+
+ if !ok || configMismatch {
if urlSpec.Spec.urlKind == envinfo.INGRESS && kClient == nil {
continue
}
@@ -614,11 +631,8 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam
}
log.Successf("URL %s successfully deleted", urlName)
urlChange = true
+ delete(urlCLUSTER, urlName)
continue
- } else {
- if !reflect.DeepEqual(val.Spec, urlSpec.Spec) {
- return errors.Errorf("config mismatch for URL with the same name %s", val.Name)
- }
}
}
diff --git a/pkg/url/url_test.go b/pkg/url/url_test.go
index 4a6869c4649..f24920f922a 100644
--- a/pkg/url/url_test.go
+++ b/pkg/url/url_test.go
@@ -777,11 +777,33 @@ func TestPush(t *testing.T) {
},
{
Name: "example-1",
- Port: 8080,
+ Port: 9090,
Secure: false,
},
},
returnedRoutes: &routev1.RouteList{},
+ createdURLs: []URL{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-app",
+ },
+ Spec: URLSpec{
+ Port: 8080,
+ Secure: false,
+ urlKind: envinfo.ROUTE,
+ },
+ },
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-1-app",
+ },
+ Spec: URLSpec{
+ Port: 9090,
+ Secure: false,
+ urlKind: envinfo.ROUTE,
+ },
+ },
+ },
},
{
name: "0 url on local config and 2 on openshift cluster",
@@ -839,6 +861,27 @@ func TestPush(t *testing.T) {
},
},
},
+ {
+ name: "2 url on local config and openshift cluster are in sync",
+ componentName: "nodejs",
+ applicationName: "app",
+ args: args{isRouteSupported: true},
+ existingConfigURLs: []config.ConfigURL{
+ {
+ Name: "example",
+ Port: 8080,
+ Secure: false,
+ },
+ {
+ Name: "example-1",
+ Port: 9100,
+ Secure: false,
+ },
+ },
+ returnedRoutes: testingutil.GetRouteListWithMultiple("nodejs", "app"),
+ deletedURLs: []URL{},
+ createdURLs: []URL{},
+ },
{
name: "0 urls on env file and cluster",
@@ -974,6 +1017,31 @@ func TestPush(t *testing.T) {
},
},
},
+ {
+ name: "2 urls on env file and openshift cluster are in sync",
+ componentName: "wildfly",
+ args: args{isRouteSupported: true, isExperimentalModeEnabled: true},
+ existingEnvInfoURLs: []envinfo.EnvInfoURL{
+ {
+ Name: "example-0",
+ Port: 8080,
+ Secure: false,
+ Host: "com",
+ Kind: envinfo.INGRESS,
+ },
+ {
+ Name: "example-1",
+ Port: 9090,
+ Secure: false,
+ Host: "com",
+ Kind: envinfo.INGRESS,
+ },
+ },
+ returnedRoutes: &routev1.RouteList{},
+ returnedIngress: fake.GetIngressListWithMultiple("wildfly"),
+ createdURLs: []URL{},
+ deletedURLs: []URL{},
+ },
{
name: "2 (1 ingress,1 route) urls on env file and 2 on openshift cluster (1 ingress,1 route), but they are different",
componentName: "nodejs",
@@ -1081,9 +1149,26 @@ func TestPush(t *testing.T) {
*fake.GetSingleIngress("example-local-0", "nodejs"),
},
},
- createdURLs: []URL{},
- deletedURLs: []URL{},
- wantErr: true,
+ createdURLs: []URL{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-local-0",
+ },
+ Spec: URLSpec{
+ Port: 8080,
+ Secure: false,
+ urlKind: envinfo.ROUTE,
+ },
+ },
+ },
+ deletedURLs: []URL{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-local-0",
+ },
+ },
+ },
+ wantErr: false,
},
{
name: "url with same name exists on config and cluster but with different specs",
@@ -1103,9 +1188,26 @@ func TestPush(t *testing.T) {
},
},
returnedIngress: &extensionsv1.IngressList{},
- createdURLs: []URL{},
- deletedURLs: []URL{},
- wantErr: true,
+ createdURLs: []URL{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-local-0-app",
+ },
+ Spec: URLSpec{
+ Port: 8080,
+ Secure: false,
+ urlKind: envinfo.ROUTE,
+ },
+ },
+ },
+ deletedURLs: []URL{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-local-0-app",
+ },
+ },
+ },
+ wantErr: false,
},
{
@@ -1339,6 +1441,16 @@ func TestPush(t *testing.T) {
t.Errorf("route is not supproted, total actions on the routeClient should be 0")
}
}
+
+ if len(tt.createdURLs) == 0 && len(tt.deletedURLs) == 0 {
+ if len(fakeClientSet.RouteClientset.Actions()) > 1 {
+ t.Errorf("when urls are in sync, total action for route client set should be less than 1")
+ }
+
+ if len(fakeClientSet.Kubernetes.Actions()) > 1 {
+ t.Errorf("when urls are in snyc, total action for kubernetes client set should be less than 1")
+ }
+ }
}
})
}
diff --git a/pkg/util/util.go b/pkg/util/util.go
index 2dce6cf36c6..2c7746a9749 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -33,7 +33,10 @@ import (
)
// HTTPRequestTimeout configures timeout of all HTTP requests
-const HTTPRequestTimeout = 10 * time.Second
+const (
+ HTTPRequestTimeout = 20 * time.Second // HTTPRequestTimeout configures timeout of all HTTP requests
+ ResponseHeaderTimeout = 10 * time.Second // ResponseHeaderTimeout is the timeout to retrieve the server's response headers
+)
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz")
@@ -680,7 +683,10 @@ func GetRemoteFilesMarkedForDeletion(delSrcRelPaths []string, remoteFolder strin
// HTTPGetRequest uses url to get file contents
func HTTPGetRequest(url string) ([]byte, error) {
- var httpClient = &http.Client{Timeout: HTTPRequestTimeout}
+ var httpClient = &http.Client{Transport: &http.Transport{
+ ResponseHeaderTimeout: ResponseHeaderTimeout,
+ },
+ Timeout: HTTPRequestTimeout}
resp, err := httpClient.Get(url)
if err != nil {
return nil, err
@@ -924,7 +930,9 @@ func DownloadFile(url string, filepath string) error {
defer out.Close() // #nosec G307
// Get the data
- var httpClient = &http.Client{Timeout: HTTPRequestTimeout}
+ var httpClient = &http.Client{Transport: &http.Transport{
+ ResponseHeaderTimeout: ResponseHeaderTimeout,
+ }, Timeout: HTTPRequestTimeout}
resp, err := httpClient.Get(url)
if err != nil {
return err
@@ -982,3 +990,17 @@ func CheckKubeConfigExist() bool {
return false
}
+
+// ValidateURL validates the URL
+func ValidateURL(sourceURL string) error {
+ u, err := url.Parse(sourceURL)
+ if err != nil {
+ return err
+ }
+
+ if len(u.Host) == 0 || len(u.Scheme) == 0 {
+ return errors.New("URL is invalid")
+ }
+
+ return nil
+}
diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go
index 94f5b88c941..1dae55a141f 100644
--- a/pkg/util/util_test.go
+++ b/pkg/util/util_test.go
@@ -1614,3 +1614,41 @@ func TestGetGitHubZipURL(t *testing.T) {
}
}
*/
+
+func TestValidateURL(t *testing.T) {
+ tests := []struct {
+ name string
+ url string
+ wantErr bool
+ }{
+ {
+ name: "Case 1: Valid URL",
+ url: "http://www.example.com/",
+ wantErr: false,
+ },
+ {
+ name: "Case 2: Invalid URL - No host",
+ url: "http://",
+ wantErr: true,
+ },
+ {
+ name: "Case 3: Invalid URL - No scheme",
+ url: "://www.example.com/",
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotErr := false
+ got := ValidateURL(tt.url)
+ if got != nil {
+ gotErr = true
+ }
+
+ if !reflect.DeepEqual(gotErr, tt.wantErr) {
+ t.Errorf("Got %v, want %v", got, tt.wantErr)
+ }
+ })
+ }
+}
diff --git a/tests/examples/source/devfiles/nodejs/project/app/app.js b/tests/examples/source/devfiles/nodejs/project/app/app.js
new file mode 100644
index 00000000000..42ff4183f17
--- /dev/null
+++ b/tests/examples/source/devfiles/nodejs/project/app/app.js
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012-2019 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+
+/*eslint-env node*/
+
+var express = require('express');
+var app = express();
+
+app.get('/', function (req, res) {
+ res.send('Hello World!');
+});
+
+app.listen(3000, function () {
+ console.log('Example app listening on port 3000!');
+});
diff --git a/tests/examples/source/devfiles/nodejs/project/package.json b/tests/examples/source/devfiles/nodejs/project/package.json
new file mode 100644
index 00000000000..2c28053506f
--- /dev/null
+++ b/tests/examples/source/devfiles/nodejs/project/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "nodejs-sample",
+ "version": "1.0.0",
+ "description": "",
+ "main": "app/app.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "EPL-2.0",
+ "dependencies": {
+ "express": "^4.13.4"
+ }
+}
diff --git a/tests/examples/source/devfiles/springboot/project/.gitignore b/tests/examples/source/devfiles/springboot/project/.gitignore
new file mode 100644
index 00000000000..18d2ca6cdc6
--- /dev/null
+++ b/tests/examples/source/devfiles/springboot/project/.gitignore
@@ -0,0 +1,4 @@
+target/
+.classpath
+.project
+.settings/
diff --git a/tests/examples/source/devfiles/springboot/project/pom.xml b/tests/examples/source/devfiles/springboot/project/pom.xml
new file mode 100644
index 00000000000..5dc6fa1723a
--- /dev/null
+++ b/tests/examples/source/devfiles/springboot/project/pom.xml
@@ -0,0 +1,84 @@
+
+
+ 4.0.0
+
+ projects
+ sprtest1
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 1.8
+ 1.8
+ Dalston.SR4
+
+ sprtest1
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.15.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-hystrix
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.ibm.runtimetools
+ javametrics-spring
+ [1.1,2.0)
+
+
+ com.ibm.runtimetools
+ javametrics-agent
+ [1.1,2.0)
+
+
+ org.glassfish
+ javax.json
+ 1.0.4
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/tests/examples/source/devfiles/springboot/project/src/main/java/application/Info.java b/tests/examples/source/devfiles/springboot/project/src/main/java/application/Info.java
new file mode 100644
index 00000000000..7cb2fb1b983
--- /dev/null
+++ b/tests/examples/source/devfiles/springboot/project/src/main/java/application/Info.java
@@ -0,0 +1,17 @@
+package application;
+
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+
+@Component
+public class Info {
+
+ @EventListener(ApplicationReadyEvent.class)
+ public void contextRefreshedEvent() {
+ System.out.println("The following endpoints are available by default :-");
+ System.out.println(" Health : http://localhost:8080/health");
+ System.out.println(" Application : http://localhost:8080/v1/");
+ }
+
+}
diff --git a/tests/examples/source/devfiles/springboot/project/src/main/java/application/SBApplication.java b/tests/examples/source/devfiles/springboot/project/src/main/java/application/SBApplication.java
new file mode 100644
index 00000000000..1b28be333d6
--- /dev/null
+++ b/tests/examples/source/devfiles/springboot/project/src/main/java/application/SBApplication.java
@@ -0,0 +1,14 @@
+package application;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(basePackages = {"application", "com.ibm.javametrics.spring"})
+public class SBApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SBApplication.class, args);
+ }
+}
diff --git a/tests/examples/source/devfiles/springboot/project/src/main/java/application/rest/v1/Example.java b/tests/examples/source/devfiles/springboot/project/src/main/java/application/rest/v1/Example.java
new file mode 100644
index 00000000000..99819f264d1
--- /dev/null
+++ b/tests/examples/source/devfiles/springboot/project/src/main/java/application/rest/v1/Example.java
@@ -0,0 +1,23 @@
+package application.rest.v1;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ResponseBody;
+import java.util.ArrayList;
+import java.util.List;
+
+@RestController
+public class Example {
+
+
+ @RequestMapping("v1")
+ public @ResponseBody ResponseEntity example() {
+ List list = new ArrayList<>();
+ //return a simple list of strings
+ list.add("Congratulations, your application is up and running.");
+ return new ResponseEntity(list.toString(), HttpStatus.OK);
+ }
+
+}
diff --git a/tests/examples/source/devfiles/springboot/project/src/main/resources/application-local.properties b/tests/examples/source/devfiles/springboot/project/src/main/resources/application-local.properties
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/examples/source/devfiles/springboot/project/src/main/resources/application.properties b/tests/examples/source/devfiles/springboot/project/src/main/resources/application.properties
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/examples/source/openjdk-sb-postgresql/.gitignore b/tests/examples/source/openjdk-sb-postgresql/.gitignore
new file mode 100644
index 00000000000..18d2ca6cdc6
--- /dev/null
+++ b/tests/examples/source/openjdk-sb-postgresql/.gitignore
@@ -0,0 +1,4 @@
+target/
+.classpath
+.project
+.settings/
diff --git a/tests/examples/source/openjdk/.gitignore b/tests/examples/source/openjdk/.gitignore
new file mode 100644
index 00000000000..18d2ca6cdc6
--- /dev/null
+++ b/tests/examples/source/openjdk/.gitignore
@@ -0,0 +1,4 @@
+target/
+.classpath
+.project
+.settings/
diff --git a/tests/examples/source/wildfly/.gitignore b/tests/examples/source/wildfly/.gitignore
new file mode 100644
index 00000000000..18d2ca6cdc6
--- /dev/null
+++ b/tests/examples/source/wildfly/.gitignore
@@ -0,0 +1,4 @@
+target/
+.classpath
+.project
+.settings/
diff --git a/tests/helper/helper_docker.go b/tests/helper/helper_docker.go
index f5fbfcfc64b..11940692b41 100644
--- a/tests/helper/helper_docker.go
+++ b/tests/helper/helper_docker.go
@@ -1,6 +1,7 @@
package helper
import (
+ "encoding/json"
"fmt"
"strings"
@@ -84,6 +85,19 @@ func (d *DockerRunner) GetVolumesByLabel(label string) []string {
return containers
}
+// VolumeExists returns true if a volume with the given name exists, false otherwise.
+func (d *DockerRunner) VolumeExists(name string) bool {
+ vols := d.ListVolumes()
+
+ for _, vol := range vols {
+ if vol == name {
+ return true
+ }
+ }
+ return false
+
+}
+
// GetVolumesByCompStorageName returns the list of volumes associated with a specific devfile volume in a component
func (d *DockerRunner) GetVolumesByCompStorageName(component string, storageName string) []string {
fmt.Fprintf(GinkgoWriter, "Listing Docker volumes with comp %s and storage name %s", component, storageName)
@@ -96,7 +110,20 @@ func (d *DockerRunner) GetVolumesByCompStorageName(component string, storageName
return containers
}
-// IsVolumeMountedInContainer returns true if the specified volume is moutned in the container associated with specified component and alias
+// InspectVolume returns a map-representation of the JSON returned by the 'docker inspect volume' command
+func (d *DockerRunner) InspectVolume(volumeName string) []map[string]interface{} {
+
+ fmt.Fprintf(GinkgoWriter, "Inspecting volume %s", volumeName)
+ output := CmdShouldPass(d.path, "inspect", volumeName)
+
+ var result []map[string]interface{}
+ err := json.Unmarshal([]byte(output), &result)
+ Expect(err).NotTo(HaveOccurred())
+
+ return result
+}
+
+// IsVolumeMountedInContainer returns true if the specified volume is mounted in the container associated with specified component and alias
func (d *DockerRunner) IsVolumeMountedInContainer(volumeName string, component string, alias string) bool {
// Get the container ID of the specified component and alias
containers := d.GetRunningContainersByCompAlias(component, alias)
@@ -108,47 +135,74 @@ func (d *DockerRunner) IsVolumeMountedInContainer(volumeName string, component s
return strings.Contains(mounts, volumeName)
}
-// ListVolumesOfComponentAndType lists all volumes that match the expected component/type labels
-func (d *DockerRunner) ListVolumesOfComponentAndType(componentLabel string, typeLabel string) []string {
+// GetSourceAndStorageVolumesByComponent lists only the volumes that are associated with this component
+// and contain either the 'type' or 'storage-name' fields.
+func (d *DockerRunner) GetSourceAndStorageVolumesByComponent(componentLabel string) []string {
- fmt.Fprintf(GinkgoWriter, "Listing volumes with component label %s and type label %s", componentLabel, typeLabel)
- session := CmdRunner(d.path, "volume", "ls", "-q", "--filter", "label=component="+componentLabel, "--filter", "label=type="+typeLabel)
+ result := []string{}
- session.Wait()
- if session.ExitCode() == 0 {
+ volumeList := d.GetVolumesByLabel("component=" + componentLabel)
+ if len(volumeList) == 0 {
+ return result
+ }
+
+ fmt.Fprintf(GinkgoWriter, "Removing volumes with component label %s", componentLabel)
- volumes := strings.Fields(strings.TrimSpace(string(session.Out.Contents())))
+ for _, volumeName := range volumeList {
+
+ // Only return volumes that contain the component label, and either 'type' or 'storage-name'
+ volumeJSON := d.InspectVolume(volumeName)
+ volumeLabels := (volumeJSON[0]["Labels"]).(map[string]interface{})
+
+ match := false
+ if typeValue, ok := volumeLabels["type"]; ok {
+ match = match || typeValue == "projects"
+ }
+ if _, ok := volumeLabels["storage-name"]; ok {
+ match = true
+ }
- return volumes
+ if match {
+ result = append(result, volumeName)
+ }
}
- return []string{}
+
+ return result
+
}
-// RemoveVolumesByComponentAndType removes any volumes that match specified component and type labels
-func (d *DockerRunner) RemoveVolumesByComponentAndType(componentLabel string, typeLabel string) string {
+// RemoveVolumeByName removes a specific volume by name
+func (d *DockerRunner) RemoveVolumeByName(volumeName string) *gexec.Session {
+ fmt.Fprintf(GinkgoWriter, "Removing volume with ID %s", volumeName)
- volumes := d.ListVolumesOfComponentAndType(componentLabel, typeLabel)
+ session := CmdRunner(d.path, "volume", "rm", "-f", volumeName)
+ session.Wait()
- if len(volumes) == 0 {
+ return session
+}
+
+// RemoveVolumesByComponent removes source/storage volumes that match specified component
+func (d *DockerRunner) RemoveVolumesByComponent(componentLabel string) string {
+
+ volumeList := d.GetSourceAndStorageVolumesByComponent(componentLabel)
+ if len(volumeList) == 0 {
return ""
}
- fmt.Fprintf(GinkgoWriter, "Removing volumes with component label %s and type label %s", componentLabel, typeLabel)
- output := ""
+ fmt.Fprintf(GinkgoWriter, "Removing volumes with component label %s", componentLabel)
- for _, volume := range volumes {
+ output := ""
- fmt.Fprintf(GinkgoWriter, "Removing volume with ID %s", volume)
+ for _, volumeName := range volumeList {
- session := CmdRunner(d.path, "volume", "rm", "-f", volume)
- session.Wait()
+ session := d.RemoveVolumeByName(volumeName)
sessionOut := strings.TrimSpace(string(session.Out.Contents()))
if session.ExitCode() == 0 {
output += sessionOut + " "
} else {
- fmt.Fprintf(GinkgoWriter, "Non-zero error code on removing volume with component label %s and type label %s, output: %s", componentLabel, typeLabel, sessionOut)
+ fmt.Fprintf(GinkgoWriter, "Non-zero error code on removing volume with component label %s, output: %s", componentLabel, sessionOut)
}
}
@@ -170,3 +224,19 @@ func (d *DockerRunner) StopContainers(label string) {
}
}
+
+// CreateVolume creates an empty volume with the given name and labels
+func (d *DockerRunner) CreateVolume(volumeName string, labels []string) {
+ fmt.Fprintf(GinkgoWriter, "Creating volume %s with labels %v", volumeName, labels)
+
+ args := []string{"volume", "create"}
+
+ for _, label := range labels {
+ args = append(args, "--label", label)
+ }
+
+ args = append(args, volumeName)
+
+ CmdShouldPass(d.path, args...)
+
+}
diff --git a/tests/integration/cmd_app_test.go b/tests/integration/cmd_app_test.go
index 016a8c3ee0a..75f010b366f 100644
--- a/tests/integration/cmd_app_test.go
+++ b/tests/integration/cmd_app_test.go
@@ -51,7 +51,7 @@ var _ = Describe("odo app command tests", func() {
appList := helper.CmdShouldPass("odo", "app", "list", "--project", project)
Expect(appList).To(ContainSubstring("There are no applications deployed"))
actual := helper.CmdShouldPass("odo", "app", "list", "-o", "json", "--project", project)
- desired := `{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[]}`
+ desired := `{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[]}`
Expect(desired).Should(MatchJSON(actual))
appDelete := helper.CmdShouldFail("odo", "app", "delete", "test", "--project", project, "-f")
@@ -78,11 +78,11 @@ var _ = Describe("odo app command tests", func() {
Expect(appListOutput).To(ContainSubstring(appName))
actualCompListJSON := helper.CmdShouldPass("odo", "list", "-o", "json")
- desiredCompListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[{"kind":"Component","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"nodejs","creationTimestamp":null, "namespace":"%s"},"spec":{"type":"nodejs","app":"app","sourceType": "local","env":[{"name":"DEBUG_PORT","value":"5858"}]},"status":{"state":"Pushed"}}]}`, project)
+ desiredCompListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"Component","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"nodejs","creationTimestamp":null, "namespace":"%s"},"spec":{"type":"nodejs","app":"app","sourceType": "local","env":[{"name":"DEBUG_PORT","value":"5858"}]},"status":{"state":"Pushed"}}]}`, project)
Expect(desiredCompListJSON).Should(MatchJSON(actualCompListJSON))
helper.CmdShouldPass("odo", "app", "describe")
- desiredDesAppJSON := fmt.Sprintf(`{"kind":"Application","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"myapp","namespace":"%s","creationTimestamp":null},"spec":{}}`, project)
+ desiredDesAppJSON := fmt.Sprintf(`{"kind":"Application","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myapp","namespace":"%s","creationTimestamp":null},"spec":{}}`, project)
actualDesAppJSON := helper.CmdShouldPass("odo", "app", "describe", "myapp", "-o", "json")
Expect(desiredDesAppJSON).Should(MatchJSON(actualDesAppJSON))
@@ -113,12 +113,12 @@ var _ = Describe("odo app command tests", func() {
appListOutput := helper.CmdShouldPass("odo", "app", "list", "--project", project)
Expect(appListOutput).To(ContainSubstring(appName))
actualCompListJSON := helper.CmdShouldPass("odo", "app", "list", "-o", "json", "--project", project)
- //desiredCompListJSON := `{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[]}`
- desiredCompListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[{"kind":"Application","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"app","namespace":"%s","creationTimestamp":null},"spec":{"components":["%s"]}}]}`, project, cmpName)
+ //desiredCompListJSON := `{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[]}`
+ desiredCompListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"Application","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"app","namespace":"%s","creationTimestamp":null},"spec":{"components":["%s"]}}]}`, project, cmpName)
Expect(desiredCompListJSON).Should(MatchJSON(actualCompListJSON))
helper.CmdShouldPass("odo", "app", "describe", appName, "--project", project)
- desiredDesAppJSON := fmt.Sprintf(`{"kind":"Application","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"%s","namespace":"%s","creationTimestamp":null},"spec":{"components":["%s"]}}`, appName, project, cmpName)
+ desiredDesAppJSON := fmt.Sprintf(`{"kind":"Application","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"%s","namespace":"%s","creationTimestamp":null},"spec":{"components":["%s"]}}`, appName, project, cmpName)
actualDesAppJSON := helper.CmdShouldPass("odo", "app", "describe", appName, "--project", project, "-o", "json")
Expect(desiredDesAppJSON).Should(MatchJSON(actualDesAppJSON))
diff --git a/tests/integration/cmd_storage_test.go b/tests/integration/cmd_storage_test.go
index 93d86533e6b..1ad9a4dc4fb 100644
--- a/tests/integration/cmd_storage_test.go
+++ b/tests/integration/cmd_storage_test.go
@@ -130,11 +130,11 @@ var _ = Describe("odo storage command tests", func() {
helper.CopyExample(filepath.Join("source", "wildfly"), context)
helper.CmdShouldPass("odo", "component", "create", "wildfly", "wildfly", "--app", "wildflyapp", "--project", project, "--context", context)
actualJSONStorage := helper.CmdShouldPass("odo", "storage", "create", "mystorage", "--path=/opt/app-root/src/storage/", "--size=1Gi", "--context", context, "-o", "json")
- desiredJSONStorage := `{"kind":"storage","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"mystorage","creationTimestamp":null},"spec":{"size":"1Gi","path":"/opt/app-root/src/storage/"}}`
+ desiredJSONStorage := `{"kind":"storage","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"mystorage","creationTimestamp":null},"spec":{"size":"1Gi","path":"/opt/app-root/src/storage/"}}`
Expect(desiredJSONStorage).Should(MatchJSON(actualJSONStorage))
actualStorageList := helper.CmdShouldPass("odo", "storage", "list", "--context", context, "-o", "json")
- desiredStorageList := `{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[{"kind":"storage","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"mystorage","creationTimestamp":null},"spec":{"size":"1Gi","path":"/opt/app-root/src/storage/"},"status":"Not Pushed"}]}`
+ desiredStorageList := `{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"storage","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"mystorage","creationTimestamp":null},"spec":{"size":"1Gi","path":"/opt/app-root/src/storage/"},"status":"Not Pushed"}]}`
Expect(desiredStorageList).Should(MatchJSON(actualStorageList))
helper.CmdShouldPass("odo", "storage", "delete", "mystorage", "--context", context, "-f")
diff --git a/tests/integration/cmd_url_test.go b/tests/integration/cmd_url_test.go
index 7d29e1697f9..d72879f92f3 100644
--- a/tests/integration/cmd_url_test.go
+++ b/tests/integration/cmd_url_test.go
@@ -131,7 +131,7 @@ var _ = Describe("odo url command tests", func() {
actualURLListJSON := helper.CmdShouldPass("odo", "url", "list", "-o", "json")
fullURLPath := helper.DetermineRouteURL("")
pathNoHTTP := strings.Split(fullURLPath, "//")[1]
- desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"http","port":8080,"secure":false},"status":{"state": "Pushed"}}]}`, pathNoHTTP)
+ desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"http","port":8080,"secure":false},"status":{"state": "Pushed"}}]}`, pathNoHTTP)
Expect(desiredURLListJSON).Should(MatchJSON(actualURLListJSON))
})
@@ -144,7 +144,7 @@ var _ = Describe("odo url command tests", func() {
actualURLListJSON := helper.CmdShouldPass("odo", "url", "list", "-o", "json")
fullURLPath := helper.DetermineRouteURL("")
pathNoHTTP := strings.Split(fullURLPath, "//")[1]
- desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"https","port":8080,"secure":true},"status":{"state": "Pushed"}}]}`, pathNoHTTP)
+ desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"https","port":8080,"secure":true},"status":{"state": "Pushed"}}]}`, pathNoHTTP)
Expect(desiredURLListJSON).Should(MatchJSON(actualURLListJSON))
})
})
diff --git a/tests/integration/component.go b/tests/integration/component.go
index 485fd858502..cd459d5241f 100644
--- a/tests/integration/component.go
+++ b/tests/integration/component.go
@@ -135,7 +135,7 @@ func componentTests(args ...string) {
contextPath = strings.TrimSpace(context)
}
// this orders the json
- desired, err := helper.Unindented(fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"nodejs","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"nodejs","sourceType": "local","ports":["8080/TCP"]},"status":{"context":"%s","state":"Not Pushed"}}`, project, contextPath))
+ desired, err := helper.Unindented(fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"nodejs","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"nodejs","sourceType": "local","ports":["8080/TCP"]},"status":{"context":"%s","state":"Not Pushed"}}`, project, contextPath))
Expect(err).Should(BeNil())
actual, err := helper.Unindented(helper.CmdShouldPass("odo", append(args, "list", "-o", "json", "--path", filepath.Dir(context))...))
@@ -175,11 +175,11 @@ func componentTests(args ...string) {
helper.DeleteDir(context2)
helper.DeleteProject(project2)
// this orders the json
- expected, err := helper.Unindented(fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"nodejs","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"nodejs","sourceType": "local","ports":["8080/TCP"]},"status":{"context":"%s","state":"Pushed"}}`, project, contextPath))
+ expected, err := helper.Unindented(fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"nodejs","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"nodejs","sourceType": "local","ports":["8080/TCP"]},"status":{"context":"%s","state":"Pushed"}}`, project, contextPath))
Expect(err).Should(BeNil())
Expect(actual).Should(ContainSubstring(expected))
// this orders the json
- expected, err = helper.Unindented(fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"python","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"python","sourceType": "local","ports":["8080/TCP"]},"status":{"context":"%s","state":"Pushed"}}`, project2, contextPath2))
+ expected, err = helper.Unindented(fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"python","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"python","sourceType": "local","ports":["8080/TCP"]},"status":{"context":"%s","state":"Pushed"}}`, project2, contextPath2))
Expect(err).Should(BeNil())
Expect(actual).Should(ContainSubstring(expected))
@@ -199,7 +199,7 @@ func componentTests(args ...string) {
cmpList := helper.CmdShouldPass("odo", append(args, "list", "--project", project)...)
Expect(cmpList).To(ContainSubstring("cmp-git"))
actualCompListJSON := helper.CmdShouldPass("odo", append(args, "list", "--project", project, "-o", "json")...)
- desiredCompListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.openshift.io/v1alpha1","metadata":{},"items":[{"kind":"Component","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"cmp-git","namespace":"%s","creationTimestamp":null},"spec":{"app":"testing","type":"nodejs","source":"https://github.com/openshift/nodejs-ex","sourceType": "git","env":[{"name":"DEBUG_PORT","value":"5858"}]},"status":{"state":"Pushed"}}]}`, project)
+ desiredCompListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"Component","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"cmp-git","namespace":"%s","creationTimestamp":null},"spec":{"app":"testing","type":"nodejs","source":"https://github.com/openshift/nodejs-ex","sourceType": "git","env":[{"name":"DEBUG_PORT","value":"5858"}]},"status":{"state":"Pushed"}}]}`, project)
Expect(desiredCompListJSON).Should(MatchJSON(actualCompListJSON))
cmpAllList := helper.CmdShouldPass("odo", append(args, "list", "--all-apps")...)
Expect(cmpAllList).To(ContainSubstring("cmp-git"))
@@ -249,7 +249,7 @@ func componentTests(args ...string) {
cmpDescribeJSON, err := helper.Unindented(helper.CmdShouldPass("odo", append(args, "describe", "-o", "json", "--context", context)...))
Expect(err).Should(BeNil())
- expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.openshift.io/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","source": "https://github.com/openshift/nodejs-ex","sourceType": "git","urls": {"kind": "List", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {}, "items": [{"kind": "url", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {"name": "url-1", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false}, "status": {"state": "Not Pushed"}}, {"kind": "url", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {"name": "url-2", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false}, "status": {"state": "Not Pushed"}}]},"storages": {"kind": "List", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {}, "items": [{"kind": "storage", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {"name": "storage-1", "creationTimestamp": null}, "spec": {"size": "1Gi", "path": "/data1"}}]},"ports": ["8080/TCP", "8080/TCP"]},"status": {"state": "Not Pushed"}}`)
+ expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.dev/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","source": "https://github.com/openshift/nodejs-ex","sourceType": "git","urls": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": [{"kind": "url", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "url-1", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false}, "status": {"state": "Not Pushed"}}, {"kind": "url", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "url-2", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false}, "status": {"state": "Not Pushed"}}]},"storages": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": [{"kind": "storage", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "storage-1", "creationTimestamp": null}, "spec": {"size": "1Gi", "path": "/data1"}}]},"ports": ["8080/TCP", "8080/TCP"]},"status": {"state": "Not Pushed"}}`)
Expect(err).Should(BeNil())
Expect(cmpDescribeJSON).To(Equal(expected))
@@ -264,7 +264,7 @@ func componentTests(args ...string) {
helper.CopyExample(filepath.Join("source", "nodejs"), context)
cmpDescribeJSON, err := helper.Unindented(helper.CmdShouldPass("odo", append(args, "create", "nodejs", "cmp-git", "--project", project, "--context", context, "--app", "testing", "-o", "json")...))
Expect(err).Should(BeNil())
- expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.openshift.io/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","source": "file://./","sourceType": "local","ports": ["8080/TCP"]}, "status": {"state": "Not Pushed"}}`)
+ expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.dev/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","source": "file://./","sourceType": "local","ports": ["8080/TCP"]}, "status": {"state": "Not Pushed"}}`)
Expect(err).Should(BeNil())
Expect(cmpDescribeJSON).To(Equal(expected))
helper.CmdShouldPass("odo", append(args, "delete", "-f", "--all", "--context", context)...)
@@ -274,7 +274,7 @@ func componentTests(args ...string) {
helper.CopyExample(filepath.Join("source", "nodejs"), context)
cmpDescribeJSON, err := helper.Unindented(helper.CmdShouldPass("odo", append(args, "create", "nodejs", "cmp-git", "--project", project, "--context", context, "--app", "testing", "-o", "json", "--now")...))
Expect(err).Should(BeNil())
- expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.openshift.io/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","sourceType": "local","env": [{"name": "DEBUG_PORT","value": "5858"}],"ports": ["8080/TCP"]}, "status": {"state": "Pushed"}}`)
+ expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.dev/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","sourceType": "local","env": [{"name": "DEBUG_PORT","value": "5858"}],"ports": ["8080/TCP"]}, "status": {"state": "Pushed"}}`)
Expect(err).Should(BeNil())
Expect(cmpDescribeJSON).To(Equal(expected))
helper.CmdShouldPass("odo", append(args, "delete", "-f", "--all", "--context", context)...)
@@ -702,7 +702,7 @@ func componentTests(args ...string) {
actualDesCompJSON := helper.CmdShouldPass("odo", append(args, "describe", cmpName, "--app", appName, "--project", project, "-o", "json")...)
- desiredDesCompJSON := fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"nodejs","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"nodejs","sourceType": "local", "urls": {"kind": "List", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {}, "items": null}, "storages": {"kind": "List", "apiVersion": "odo.openshift.io/v1alpha1", "metadata": {}, "items": null}, "env":[{"name":"DEBUG_PORT","value":"5858"}]},"status":{"state":"Pushed"}}`, project)
+ desiredDesCompJSON := fmt.Sprintf(`{"kind":"Component","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"nodejs","namespace":"%s","creationTimestamp":null},"spec":{"app":"app","type":"nodejs","sourceType": "local", "urls": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": null}, "storages": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": null}, "env":[{"name":"DEBUG_PORT","value":"5858"}]},"status":{"state":"Pushed"}}`, project)
Expect(desiredDesCompJSON).Should(MatchJSON(actualDesCompJSON))
helper.CmdShouldPass("odo", append(args, "delete", cmpName, "--app", appName, "--project", project, "-f")...)
diff --git a/tests/integration/devfile/cmd_devfile_catalog_test.go b/tests/integration/devfile/cmd_devfile_catalog_test.go
index 4b9c0cdebda..d2aa5f7a85a 100644
--- a/tests/integration/devfile/cmd_devfile_catalog_test.go
+++ b/tests/integration/devfile/cmd_devfile_catalog_test.go
@@ -48,14 +48,33 @@ var _ = Describe("odo devfile catalog command tests", func() {
Context("When executing catalog list components", func() {
It("should list all supported devfile components", func() {
output := helper.CmdShouldPass("odo", "catalog", "list", "components")
- helper.MatchAllInOutput(output, []string{"Odo Devfile Components", "java-spring-boot", "openLiberty"})
+ wantOutput := []string{
+ "Odo Devfile Components",
+ "NAME",
+ "java-spring-boot",
+ "openLiberty",
+ "DESCRIPTION",
+ "REGISTRY",
+ "SUPPORTED",
+ }
+ helper.MatchAllInOutput(output, wantOutput)
})
})
Context("When executing catalog list components with -a flag", func() {
It("should list all supported and unsupported devfile components", func() {
output := helper.CmdShouldPass("odo", "catalog", "list", "components", "-a")
- helper.MatchAllInOutput(output, []string{"Odo Devfile Components", "java-spring-boot", "java-maven", "php-mysql"})
+ wantOutput := []string{
+ "Odo Devfile Components",
+ "NAME",
+ "java-spring-boot",
+ "java-maven",
+ "php-mysql",
+ "DESCRIPTION",
+ "REGISTRY",
+ "SUPPORTED",
+ }
+ helper.MatchAllInOutput(output, wantOutput)
})
})
})
diff --git a/tests/integration/devfile/cmd_devfile_create_test.go b/tests/integration/devfile/cmd_devfile_create_test.go
index e9e58702a59..0bfdc16bfac 100644
--- a/tests/integration/devfile/cmd_devfile_create_test.go
+++ b/tests/integration/devfile/cmd_devfile_create_test.go
@@ -79,6 +79,13 @@ var _ = Describe("odo devfile create command tests", func() {
})
})
+ Context("When executing odo create with devfile component type argument and --registry flag", func() {
+ It("should successfully create the devfile component", func() {
+ componentRegistry := "DefaultDevfileRegistry"
+ helper.CmdShouldPass("odo", "create", "openLiberty", "--registry", componentRegistry)
+ })
+ })
+
Context("When executing odo create with devfile component type argument and --context flag", func() {
It("should successfully create the devfile component in the context", func() {
newContext := path.Join(context, "newContext")
diff --git a/tests/integration/devfile/cmd_devfile_delete_test.go b/tests/integration/devfile/cmd_devfile_delete_test.go
index d4819a416b8..5e67256e8eb 100644
--- a/tests/integration/devfile/cmd_devfile_delete_test.go
+++ b/tests/integration/devfile/cmd_devfile_delete_test.go
@@ -12,8 +12,7 @@ import (
)
var _ = Describe("odo devfile delete command tests", func() {
- var namespace, context, currentWorkingDirectory, componentName, projectDirPath string
- var projectDir = "/projectDir"
+ var namespace, context, currentWorkingDirectory, componentName string
// TODO: all oc commands in all devfile related test should get replaced by kubectl
// TODO: to goal is not to use "oc"
@@ -25,7 +24,6 @@ var _ = Describe("odo devfile delete command tests", func() {
namespace = helper.CreateRandProject()
context = helper.CreateNewContext()
currentWorkingDirectory = helper.Getwd()
- projectDirPath = context + projectDir
componentName = helper.RandString(6)
helper.Chdir(context)
@@ -48,12 +46,10 @@ var _ = Describe("odo devfile delete command tests", func() {
Context("when devfile delete command is executed", func() {
It("should delete the component created from the devfile and also the owned resources", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "url", "create", "example", "--host", "1.2.3.4.nip.io")
@@ -71,22 +67,20 @@ var _ = Describe("odo devfile delete command tests", func() {
Context("when devfile delete command is executed with all flag", func() {
It("should delete the component created from the devfile and also the env and odo folders and the odo-index-file.json file", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
- helper.CmdShouldPass("odo", "url", "create", "example", "--host", "1.2.3.4.nip.io", "--context", projectDirPath)
+ helper.CmdShouldPass("odo", "url", "create", "example", "--host", "1.2.3.4.nip.io", "--context", context)
helper.CmdShouldPass("odo", "delete", "--devfile", "devfile.yaml", "--project", namespace, "-f", "--all")
oc.WaitAndCheckForExistence("deployments", namespace, 1)
- files := helper.ListFilesInDir(projectDirPath)
+ files := helper.ListFilesInDir(context)
Expect(files).To(Not(ContainElement(".odo")))
})
})
diff --git a/tests/integration/devfile/cmd_devfile_push_test.go b/tests/integration/devfile/cmd_devfile_push_test.go
index 7e54b07b4ea..4fdeb66a0f8 100644
--- a/tests/integration/devfile/cmd_devfile_push_test.go
+++ b/tests/integration/devfile/cmd_devfile_push_test.go
@@ -14,8 +14,7 @@ import (
)
var _ = Describe("odo devfile push command tests", func() {
- var namespace, context, cmpName, currentWorkingDirectory, projectDirPath string
- var projectDir = "/projectDir"
+ var namespace, context, cmpName, currentWorkingDirectory string
var sourcePath = "/projects/nodejs-web-app"
// TODO: all oc commands in all devfile related test should get replaced by kubectl
@@ -28,7 +27,6 @@ var _ = Describe("odo devfile push command tests", func() {
namespace = helper.CreateRandProject()
context = helper.CreateNewContext()
currentWorkingDirectory = helper.Getwd()
- projectDirPath = context + projectDir
cmpName = helper.RandString(6)
helper.Chdir(context)
@@ -51,15 +49,12 @@ var _ = Describe("odo devfile push command tests", func() {
Context("Verify devfile push works", func() {
It("should have no errors when no endpoints within the devfile, should create a service when devfile has endpoints", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
-
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
helper.RenameFile("devfile.yaml", "devfile-old.yaml")
- helper.RenameFile("devfile-no-endpoints.yaml", "devfile.yaml")
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-no-endpoints.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
output := oc.GetServices(namespace)
Expect(output).NotTo(ContainSubstring(cmpName))
@@ -73,12 +68,10 @@ var _ = Describe("odo devfile push command tests", func() {
})
It("checks that odo push works with a devfile", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
@@ -88,18 +81,26 @@ var _ = Describe("odo devfile push command tests", func() {
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
})
- })
+ It("checks that odo push works outside of the context directory", func() {
+ helper.Chdir(currentWorkingDirectory)
+
+ helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, "--context", context, cmpName)
- Context("When devfile push command is executed", func() {
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--context", context)
+ Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
+ })
It("should not build when no changes are detected in the directory and build when a file change is detected", func() {
- utils.ExecPushToTestFileChanges(projectDirPath, cmpName, namespace)
+ utils.ExecPushToTestFileChanges(context, cmpName, namespace)
})
It("should be able to create a file, push, delete, then push again propagating the deletions", func() {
- newFilePath := filepath.Join(projectDirPath, "foobar.txt")
- newDirPath := filepath.Join(projectDirPath, "testdir")
- utils.ExecPushWithNewFileAndDir(projectDirPath, cmpName, namespace, newFilePath, newDirPath)
+ newFilePath := filepath.Join(context, "foobar.txt")
+ newDirPath := filepath.Join(context, "testdir")
+ utils.ExecPushWithNewFileAndDir(context, cmpName, namespace, newFilePath, newDirPath)
// Check to see if it's been pushed (foobar.txt abd directory testdir)
podName := oc.GetRunningPodNameByComponent(cmpName, namespace)
@@ -120,12 +121,10 @@ var _ = Describe("odo devfile push command tests", func() {
})
It("should delete the files from the container if its removed locally", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
@@ -144,7 +143,7 @@ var _ = Describe("odo devfile push command tests", func() {
},
)
Expect(statErr).ToNot(HaveOccurred())
- Expect(os.Remove(filepath.Join(projectDirPath, "app", "app.js"))).NotTo(HaveOccurred())
+ Expect(os.Remove(filepath.Join(context, "app", "app.js"))).NotTo(HaveOccurred())
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
oc.CheckCmdOpInRemoteDevfilePod(
@@ -162,11 +161,11 @@ var _ = Describe("odo devfile push command tests", func() {
})
It("should build when no changes are detected in the directory and force flag is enabled", func() {
- utils.ExecPushWithForceFlag(projectDirPath, cmpName, namespace)
+ utils.ExecPushWithForceFlag(context, cmpName, namespace)
})
It("should execute the default devbuild and devrun commands if present", func() {
- utils.ExecDefaultDevfileCommands(projectDirPath, cmpName, namespace)
+ utils.ExecDefaultDevfileCommands(context, cmpName, namespace)
// Check to see if it's been pushed (foobar.txt abd directory testdir)
podName := oc.GetRunningPodNameByComponent(cmpName, namespace)
@@ -189,61 +188,51 @@ var _ = Describe("odo devfile push command tests", func() {
})
It("should execute devinit command if present", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/maysunfaisal/springboot.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "java-spring-boot", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "springboot"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile-init.yaml"), filepath.Join(context, "devfile.yaml"))
- output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile-init.yaml", "--namespace", namespace)
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
Expect(output).To(ContainSubstring("Executing devinit command \"echo hello"))
Expect(output).To(ContainSubstring("Executing devbuild command \"/artifacts/bin/build-container-full.sh\""))
Expect(output).To(ContainSubstring("Executing devrun command \"/artifacts/bin/start-server.sh\""))
})
It("should execute devinit and devrun commands if present", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/maysunfaisal/springboot.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "java-spring-boot", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "springboot"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile-init-without-build.yaml"), filepath.Join(context, "devfile.yaml"))
- output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile-init-without-build.yaml", "--namespace", namespace)
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
Expect(output).To(ContainSubstring("Executing devinit command \"echo hello"))
Expect(output).To(ContainSubstring("Executing devrun command \"/artifacts/bin/start-server.sh\""))
})
It("should only execute devinit command once if component is already created", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/maysunfaisal/springboot.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "java-spring-boot", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "springboot"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile-init.yaml"), filepath.Join(context, "devfile.yaml"))
- output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile-init.yaml", "--namespace", namespace)
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
Expect(output).To(ContainSubstring("Executing devinit command \"echo hello"))
Expect(output).To(ContainSubstring("Executing devbuild command \"/artifacts/bin/build-container-full.sh\""))
Expect(output).To(ContainSubstring("Executing devrun command \"/artifacts/bin/start-server.sh\""))
// Need to force so build and run get triggered again with the component already created.
- output = helper.CmdShouldPass("odo", "push", "--devfile", "devfile-init.yaml", "--namespace", namespace, "-f")
+ output = helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace, "-f")
Expect(output).NotTo(ContainSubstring("Executing devinit command \"echo hello"))
Expect(output).To(ContainSubstring("Executing devbuild command \"/artifacts/bin/build-container-full.sh\""))
Expect(output).To(ContainSubstring("Executing devrun command \"/artifacts/bin/start-server.sh\""))
})
It("should be able to handle a missing devinit command", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
- helper.RenameFile("devfile.yaml", "devfile-old.yaml")
- helper.RenameFile("devfile-without-devinit.yaml", "devfile.yaml")
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-without-devinit.yaml"), filepath.Join(context, "devfile.yaml"))
output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
Expect(output).NotTo(ContainSubstring("Executing devinit command"))
@@ -252,34 +241,30 @@ var _ = Describe("odo devfile push command tests", func() {
})
It("should be able to handle a missing devbuild command", func() {
- utils.ExecWithMissingBuildCommand(projectDirPath, cmpName, namespace)
+ utils.ExecWithMissingBuildCommand(context, cmpName, namespace)
})
It("should error out on a missing devrun command", func() {
- utils.ExecWithMissingRunCommand(projectDirPath, cmpName, namespace)
+ utils.ExecWithMissingRunCommand(context, cmpName, namespace)
})
It("should be able to push using the custom commands", func() {
- utils.ExecWithCustomCommand(projectDirPath, cmpName, namespace)
+ utils.ExecWithCustomCommand(context, cmpName, namespace)
})
It("should error out on a wrong custom commands", func() {
- utils.ExecWithWrongCustomCommand(projectDirPath, cmpName, namespace)
+ utils.ExecWithWrongCustomCommand(context, cmpName, namespace)
})
It("should not restart the application if restart is false", func() {
- utils.ExecWithRestartAttribute(projectDirPath, cmpName, namespace)
+ utils.ExecWithRestartAttribute(context, cmpName, namespace)
})
It("should create pvc and reuse if it shares the same devfile volume name", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
- helper.RenameFile("devfile.yaml", "devfile-old.yaml")
- helper.RenameFile("devfile-with-volumes.yaml", "devfile.yaml")
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-volumes.yaml"), filepath.Join(context, "devfile.yaml"))
output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
Expect(output).To(ContainSubstring("Executing devinit command"))
@@ -345,7 +330,6 @@ var _ = Describe("odo devfile push command tests", func() {
}
Expect(volumesMatched).To(Equal(true))
})
-
})
})
diff --git a/tests/integration/devfile/cmd_devfile_registry_test.go b/tests/integration/devfile/cmd_devfile_registry_test.go
new file mode 100644
index 00000000000..85c27e0297c
--- /dev/null
+++ b/tests/integration/devfile/cmd_devfile_registry_test.go
@@ -0,0 +1,93 @@
+package devfile
+
+import (
+ "os"
+ "path/filepath"
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/openshift/odo/tests/helper"
+)
+
+var _ = Describe("odo devfile registry command tests", func() {
+ var project string
+ var context string
+ var currentWorkingDirectory string
+ const registryName string = "RegistryName"
+ const addRegistryURL string = "https://raw.githubusercontent.com/GeekArthur/registry/master"
+ const updateRegistryURL string = "http://www.example.com/update"
+
+ // This is run after every Spec (It)
+ var _ = BeforeEach(func() {
+ SetDefaultEventuallyTimeout(10 * time.Minute)
+ context = helper.CreateNewContext()
+ os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
+ helper.CmdShouldPass("odo", "preference", "set", "Experimental", "true")
+ if os.Getenv("KUBERNETES") == "true" {
+ project = helper.CreateRandNamespace(context)
+ } else {
+ project = helper.CreateRandProject()
+ }
+ currentWorkingDirectory = helper.Getwd()
+ helper.Chdir(context)
+ })
+
+ // This is run after every Spec (It)
+ var _ = AfterEach(func() {
+ if os.Getenv("KUBERNETES") == "true" {
+ helper.DeleteNamespace(project)
+ } else {
+ helper.DeleteProject(project)
+ }
+ helper.Chdir(currentWorkingDirectory)
+ helper.DeleteDir(context)
+ })
+
+ Context("When executing registry list", func() {
+ It("Should list all default registries", func() {
+ output := helper.CmdShouldPass("odo", "registry", "list")
+ helper.MatchAllInOutput(output, []string{"CheDevfileRegistry", "DefaultDevfileRegistry"})
+ })
+ })
+
+ Context("When executing registry commands with the registry is not present", func() {
+ It("Should successfully add the registry", func() {
+ helper.CmdShouldPass("odo", "registry", "add", registryName, addRegistryURL)
+ output := helper.CmdShouldPass("odo", "registry", "list")
+ helper.MatchAllInOutput(output, []string{registryName, addRegistryURL})
+ helper.CmdShouldPass("odo", "create", "nodejs", "--registry", registryName)
+ helper.CmdShouldPass("odo", "registry", "delete", registryName, "-f")
+ })
+
+ It("Should fail to update the registry", func() {
+ helper.CmdShouldFail("odo", "registry", "update", registryName, updateRegistryURL, "-f")
+ })
+
+ It("Should fail to delete the registry", func() {
+ helper.CmdShouldFail("odo", "registry", "delete", registryName, "-f")
+ })
+ })
+
+ Context("When executing registry commands with the registry is present", func() {
+ It("Should fail to add the registry", func() {
+ helper.CmdShouldPass("odo", "registry", "add", registryName, addRegistryURL)
+ helper.CmdShouldFail("odo", "registry", "add", registryName, addRegistryURL)
+ helper.CmdShouldPass("odo", "registry", "delete", registryName, "-f")
+ })
+
+ It("Should successfully update the registry", func() {
+ helper.CmdShouldPass("odo", "registry", "add", registryName, addRegistryURL)
+ helper.CmdShouldPass("odo", "registry", "update", registryName, updateRegistryURL, "-f")
+ output := helper.CmdShouldPass("odo", "registry", "list")
+ helper.MatchAllInOutput(output, []string{registryName, updateRegistryURL})
+ helper.CmdShouldPass("odo", "registry", "delete", registryName, "-f")
+ })
+
+ It("Should successfully delete the registry", func() {
+ helper.CmdShouldPass("odo", "registry", "add", registryName, addRegistryURL)
+ helper.CmdShouldPass("odo", "registry", "delete", registryName, "-f")
+ helper.CmdShouldFail("odo", "create", "maven", "--registry", registryName)
+ })
+ })
+})
diff --git a/tests/integration/devfile/cmd_devfile_url_test.go b/tests/integration/devfile/cmd_devfile_url_test.go
index 0bada66ad17..f430f93c2c6 100644
--- a/tests/integration/devfile/cmd_devfile_url_test.go
+++ b/tests/integration/devfile/cmd_devfile_url_test.go
@@ -14,8 +14,7 @@ import (
)
var _ = Describe("odo devfile url command tests", func() {
- var namespace, context, componentName, currentWorkingDirectory, projectDirPath string
- var projectDir = "/projectDir"
+ var namespace, context, componentName, currentWorkingDirectory string
// This is run after every Spec (It)
var _ = BeforeEach(func() {
@@ -24,7 +23,6 @@ var _ = Describe("odo devfile url command tests", func() {
namespace = helper.CreateRandProject()
context = helper.CreateNewContext()
currentWorkingDirectory = helper.Getwd()
- projectDirPath = context + projectDir
componentName = helper.RandString(6)
helper.Chdir(context)
@@ -50,12 +48,10 @@ var _ = Describe("odo devfile url command tests", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
stdout = helper.CmdShouldFail("odo", "url", "list")
Expect(stdout).To(ContainSubstring("no URLs found"))
@@ -86,19 +82,17 @@ var _ = Describe("odo devfile url command tests", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress")
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
// odo url list -o json
helper.WaitForCmdOut("odo", []string{"url", "list", "-o", "json"}, 1, true, func(output string) bool {
- desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"udo.udo.io/v1alpha1","metadata":{},"items":[{"kind":"Ingress","apiVersion":"extensions/v1beta1","metadata":{"name":"%s","creationTimestamp":null},"spec":{"rules":[{"host":"%s","http":{"paths":[{"path":"/","backend":{"serviceName":"%s","servicePort":3000}}]}}]},"status":{"loadBalancer":{}}}]}`, url1, url1+"."+host, componentName)
+ desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"Ingress","apiVersion":"extensions/v1beta1","metadata":{"name":"%s","creationTimestamp":null},"spec":{"rules":[{"host":"%s","http":{"paths":[{"path":"/","backend":{"serviceName":"%s","servicePort":3000}}]}}]},"status":{"loadBalancer":{}}}]}`, url1, url1+"."+host, componentName)
if strings.Contains(output, url1) {
Expect(desiredURLListJSON).Should(MatchJSON(output))
return true
@@ -114,12 +108,10 @@ var _ = Describe("odo devfile url command tests", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--secure", "--ingress")
@@ -139,12 +131,10 @@ var _ = Describe("odo devfile url command tests", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
stdout = helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--now", "--ingress", "--devfile", "devfile.yaml")
helper.MatchAllInOutput(stdout, []string{"URL " + url1 + " created for component", "http:", url1 + "." + host})
@@ -158,22 +148,28 @@ var _ = Describe("odo devfile url command tests", func() {
url1 := helper.RandString(5)
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "url", "create", url1)
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
+ pushStdOut := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
+ Expect(pushStdOut).NotTo(ContainSubstring("successfully deleted"))
+ Expect(pushStdOut).NotTo(ContainSubstring("created"))
+ Expect(pushStdOut).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
output := helper.CmdShouldPass("oc", "get", "routes", "--namespace", namespace)
Expect(output).Should(ContainSubstring(url1))
helper.CmdShouldPass("odo", "url", "delete", url1, "-f")
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
+ pushStdOut = helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", namespace)
+ Expect(pushStdOut).NotTo(ContainSubstring("successfully deleted"))
+ Expect(pushStdOut).NotTo(ContainSubstring("created"))
+ Expect(pushStdOut).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
output = helper.CmdShouldPass("oc", "get", "routes", "--namespace", namespace)
Expect(output).ShouldNot(ContainSubstring(url1))
@@ -194,6 +190,33 @@ var _ = Describe("odo devfile url command tests", func() {
output := helper.CmdShouldPass("oc", "get", "routes", "--namespace", namespace)
Expect(output).Should(ContainSubstring(url1))
})
+
+ It("should be able to push again twice after creating and deleting a url", func() {
+ var stdOut string
+ url1 := helper.RandString(5)
+ host := helper.RandString(5) + ".com"
+
+ helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
+ helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress")
+
+ helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
+ stdOut = helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
+ Expect(stdOut).NotTo(ContainSubstring("successfully deleted"))
+ Expect(stdOut).NotTo(ContainSubstring("created"))
+ Expect(stdOut).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
+
+ helper.CmdShouldPass("odo", "url", "delete", url1, "-f")
+
+ helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
+ stdOut = helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--project", namespace)
+ Expect(stdOut).NotTo(ContainSubstring("successfully deleted"))
+ Expect(stdOut).NotTo(ContainSubstring("created"))
+ Expect(stdOut).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
+ })
})
Context("Describing urls", func() {
@@ -202,12 +225,10 @@ var _ = Describe("odo devfile url command tests", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress")
diff --git a/tests/integration/devfile/cmd_devfile_watch_test.go b/tests/integration/devfile/cmd_devfile_watch_test.go
index d05adef7e09..71c34a7db98 100644
--- a/tests/integration/devfile/cmd_devfile_watch_test.go
+++ b/tests/integration/devfile/cmd_devfile_watch_test.go
@@ -63,9 +63,9 @@ var _ = Describe("odo devfile watch command tests", func() {
// Devfile push requires experimental mode to be set
helper.CmdShouldPass("odo", "preference", "set", "Experimental", "true")
cmpName := helper.RandString(6)
+ helper.Chdir(currentWorkingDirectory)
helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, "--context", context, cmpName)
-
- output := helper.CmdShouldFail("odo", "watch", "--devfile", filepath.Join(context, "devfile.yaml"), "--context", context)
+ output := helper.CmdShouldFail("odo", "watch", "--context", context)
Expect(output).To(ContainSubstring("component does not exist. Please use `odo push` to create your component"))
})
})
diff --git a/tests/integration/devfile/docker/cmd_docker_devfile_delete_test.go b/tests/integration/devfile/docker/cmd_docker_devfile_delete_test.go
index 6a4084de2ea..5a6589f0245 100644
--- a/tests/integration/devfile/docker/cmd_docker_devfile_delete_test.go
+++ b/tests/integration/devfile/docker/cmd_docker_devfile_delete_test.go
@@ -14,8 +14,8 @@ var _ = Describe("odo docker devfile delete command tests", func() {
var context string
var currentWorkingDirectory string
var cmpName string
- var projectDir = "/projectDir"
- var projectDirPath string
+
+ var fakeVolumes []string
dockerClient := helper.NewDockerRunner("docker")
@@ -25,24 +25,49 @@ var _ = Describe("odo docker devfile delete command tests", func() {
context = helper.CreateNewContext()
currentWorkingDirectory = helper.Getwd()
cmpName = helper.RandString(6)
- projectDirPath = context + projectDir
helper.Chdir(context)
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
// Devfile commands require experimental mode to be set
helper.CmdShouldPass("odo", "preference", "set", "Experimental", "true")
helper.CmdShouldPass("odo", "preference", "set", "pushtarget", "docker")
+
+ // With our docker delete code, we want to avoid deleting volumes that we didn't create. So
+ // next we create a set of fake volumes, none of which should be deleted (eg they are out of scope) by any of the tests.
+
+ // 1) Create volume with fake component but valid type
+ volname1 := cmpName + "-fakevol1"
+ fakeVolumes = append(fakeVolumes, volname1)
+ dockerClient.CreateVolume(volname1, []string{"component=fake", "type=projects"})
+
+ // 2) Create volume with fake component but valid storage
+ volname2 := cmpName + "-fakevol2"
+ fakeVolumes = append(fakeVolumes, volname2)
+ dockerClient.CreateVolume(volname2, []string{"component=fake", "storage-name=" + volname2})
+
+ // 3) Create volume with real component but neither valid source ("type") nor valid storage
+ volname3 := cmpName + "-fakevol3"
+ fakeVolumes = append(fakeVolumes, volname3)
+ dockerClient.CreateVolume(volname3, []string{"component=" + cmpName, "type=not-projects", "storage-name-fake=" + volname3})
+
})
// Clean up after the test
// This is run after every Spec (It)
var _ = AfterEach(func() {
+ // Ensure that our fake volumes all still exist, then clean them up.
+ for _, fakeVolume := range fakeVolumes {
+ Expect(dockerClient.VolumeExists(fakeVolume)).To(Equal(true))
+ dockerClient.RemoveVolumeByName(fakeVolume)
+ }
+ fakeVolumes = []string{}
+
// Stop all containers labeled with the component name
label := "component=" + cmpName
dockerClient.StopContainers(label)
- dockerClient.RemoveVolumesByComponentAndType(cmpName, "projects")
+ dockerClient.RemoveVolumesByComponent(cmpName)
helper.Chdir(currentWorkingDirectory)
helper.DeleteDir(context)
@@ -53,49 +78,78 @@ var _ = Describe("odo docker devfile delete command tests", func() {
Context("when docker devfile delete command is executed", func() {
It("should delete the component created from the devfile and also the owned resources", func() {
-
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
Expect(dockerClient.GetRunningContainersByLabel("component=" + cmpName)).To(HaveLen(1))
- Expect(dockerClient.ListVolumesOfComponentAndType(cmpName, "projects")).To(HaveLen(1))
+ Expect(dockerClient.GetSourceAndStorageVolumesByComponent(cmpName)).To(HaveLen(1))
+
+ helper.CmdShouldPass("odo", "delete", "--devfile", "devfile.yaml", "-f")
+
+ Expect(dockerClient.GetRunningContainersByLabel("component=" + cmpName)).To(HaveLen(0))
+
+ Expect(dockerClient.GetSourceAndStorageVolumesByComponent(cmpName)).To(HaveLen(0))
+
+ })
+
+ It("should delete all the mounted volume types listed in the devfile", func() {
+
+ helper.CmdShouldPass("odo", "create", "nodejs", "--context", context, cmpName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), context)
+ helper.RenameFile("devfile.yaml", "devfile-old.yaml")
+ helper.RenameFile("devfile-with-volumes.yaml", "devfile.yaml")
+
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
+ Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
+
+ // Retrieve the volume from one of the aliases in the devfile
+ volumes := dockerClient.GetVolumesByCompStorageName(cmpName, "myvol")
+ Expect(len(volumes)).To(Equal(1))
+ vol := volumes[0]
+
+ // Verify the volume is mounted
+ volMounted := dockerClient.IsVolumeMountedInContainer(vol, cmpName, "runtime")
+ Expect(volMounted).To(Equal(true))
+
+ Expect(dockerClient.GetSourceAndStorageVolumesByComponent(cmpName)).To(HaveLen(3))
helper.CmdShouldPass("odo", "delete", "--devfile", "devfile.yaml", "-f")
Expect(dockerClient.GetRunningContainersByLabel("component=" + cmpName)).To(HaveLen(0))
- Expect(dockerClient.ListVolumesOfComponentAndType(cmpName, "projects")).To(HaveLen(0))
+ Expect(dockerClient.GetSourceAndStorageVolumesByComponent(cmpName)).To(HaveLen(0))
})
+
})
Context("when docker devfile delete command is executed with all flag", func() {
It("should delete the component created from the devfile and also the env folder", func() {
-
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
Expect(dockerClient.GetRunningContainersByLabel("component=" + cmpName)).To(HaveLen(1))
- Expect(dockerClient.ListVolumesOfComponentAndType(cmpName, "projects")).To(HaveLen(1))
+ Expect(dockerClient.GetSourceAndStorageVolumesByComponent(cmpName)).To(HaveLen(1))
helper.CmdShouldPass("odo", "delete", "--devfile", "devfile.yaml", "-f", "--all")
Expect(dockerClient.GetRunningContainersByLabel("component=" + cmpName)).To(HaveLen(0))
- Expect(dockerClient.ListVolumesOfComponentAndType(cmpName, "projects")).To(HaveLen(0))
+ Expect(dockerClient.GetSourceAndStorageVolumesByComponent(cmpName)).To(HaveLen(0))
- files := helper.ListFilesInDir(projectDirPath)
+ files := helper.ListFilesInDir(context)
Expect(files).To(Not(ContainElement(".odo")))
})
diff --git a/tests/integration/devfile/docker/cmd_docker_devfile_push_test.go b/tests/integration/devfile/docker/cmd_docker_devfile_push_test.go
index 6b64745d4e4..de4c43f3e48 100644
--- a/tests/integration/devfile/docker/cmd_docker_devfile_push_test.go
+++ b/tests/integration/devfile/docker/cmd_docker_devfile_push_test.go
@@ -13,8 +13,7 @@ import (
)
var _ = Describe("odo docker devfile push command tests", func() {
- var context, currentWorkingDirectory, cmpName, projectDirPath string
- var projectDir = "/projectDir"
+ var context, currentWorkingDirectory, cmpName string
var sourcePath = "/projects/nodejs-web-app"
dockerClient := helper.NewDockerRunner("docker")
@@ -24,7 +23,6 @@ var _ = Describe("odo docker devfile push command tests", func() {
SetDefaultEventuallyTimeout(10 * time.Minute)
context = helper.CreateNewContext()
currentWorkingDirectory = helper.Getwd()
- projectDirPath = context + projectDir
cmpName = helper.RandString(6)
helper.Chdir(context)
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
@@ -109,13 +107,13 @@ var _ = Describe("odo docker devfile push command tests", func() {
})
It("should not build when no changes are detected in the directory and build when a file change is detected", func() {
- utils.ExecPushToTestFileChanges(projectDirPath, cmpName, "")
+ utils.ExecPushToTestFileChanges(context, cmpName, "")
})
It("should be able to create a file, push, delete, then push again propagating the deletions", func() {
- newFilePath := filepath.Join(projectDirPath, "foobar.txt")
- newDirPath := filepath.Join(projectDirPath, "testdir")
- utils.ExecPushWithNewFileAndDir(projectDirPath, cmpName, "", newFilePath, newDirPath)
+ newFilePath := filepath.Join(context, "foobar.txt")
+ newDirPath := filepath.Join(context, "testdir")
+ utils.ExecPushWithNewFileAndDir(context, cmpName, "", newFilePath, newDirPath)
// Check to see if it's been pushed (foobar.txt abd directory testdir)
containers := dockerClient.GetRunningContainersByCompAlias(cmpName, "runtime")
@@ -137,11 +135,11 @@ var _ = Describe("odo docker devfile push command tests", func() {
})
It("should build when no changes are detected in the directory and force flag is enabled", func() {
- utils.ExecPushWithForceFlag(projectDirPath, cmpName, "")
+ utils.ExecPushWithForceFlag(context, cmpName, "")
})
It("should execute the default devbuild and devrun commands if present", func() {
- utils.ExecDefaultDevfileCommands(projectDirPath, cmpName, "")
+ utils.ExecDefaultDevfileCommands(context, cmpName, "")
// Check to see if it's been pushed (foobar.txt abd directory testdir)
containers := dockerClient.GetRunningContainersByCompAlias(cmpName, "runtime")
@@ -152,15 +150,12 @@ var _ = Describe("odo docker devfile push command tests", func() {
})
It("should execute the optional devinit, and devrun commands if present", func() {
-
- helper.CmdShouldPass("git", "clone", "https://github.com/maysunfaisal/springboot.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "java-spring-boot", cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "springboot"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile-init.yaml"), filepath.Join(context, "devfile.yaml"))
- output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile-init.yaml")
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
Expect(output).To(ContainSubstring("Executing devinit command \"echo hello"))
Expect(output).To(ContainSubstring("Executing devbuild command \"/artifacts/bin/build-container-full.sh\""))
Expect(output).To(ContainSubstring("Executing devrun command \"/artifacts/bin/start-server.sh\""))
@@ -174,15 +169,12 @@ var _ = Describe("odo docker devfile push command tests", func() {
})
It("should execute devinit and devrun commands if present", func() {
-
- helper.CmdShouldPass("git", "clone", "https://github.com/maysunfaisal/springboot.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "java-spring-boot", cmpName)
- helper.CopyExample(filepath.Join("source", "devfiles", "springboot"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile-init-without-build.yaml"), filepath.Join(context, "devfile.yaml"))
- output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile-init-without-build.yaml")
+ output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
Expect(output).To(ContainSubstring("Executing devinit command \"echo hello"))
Expect(output).To(ContainSubstring("Executing devrun command \"/artifacts/bin/start-server.sh\""))
@@ -195,19 +187,19 @@ var _ = Describe("odo docker devfile push command tests", func() {
})
It("should be able to handle a missing devbuild command", func() {
- utils.ExecWithMissingBuildCommand(projectDirPath, cmpName, "")
+ utils.ExecWithMissingBuildCommand(context, cmpName, "")
})
It("should error out on a missing devrun command", func() {
- utils.ExecWithMissingRunCommand(projectDirPath, cmpName, "")
+ utils.ExecWithMissingRunCommand(context, cmpName, "")
})
It("should be able to push using the custom commands", func() {
- utils.ExecWithCustomCommand(projectDirPath, cmpName, "")
+ utils.ExecWithCustomCommand(context, cmpName, "")
})
It("should error out on a wrong custom commands", func() {
- utils.ExecWithWrongCustomCommand(projectDirPath, cmpName, "")
+ utils.ExecWithWrongCustomCommand(context, cmpName, "")
})
})
diff --git a/tests/integration/devfile/docker/cmd_docker_devfile_url_test.go b/tests/integration/devfile/docker/cmd_docker_devfile_url_test.go
index bc8a2757fc0..bf5c5fcc8c8 100644
--- a/tests/integration/devfile/docker/cmd_docker_devfile_url_test.go
+++ b/tests/integration/devfile/docker/cmd_docker_devfile_url_test.go
@@ -13,8 +13,7 @@ import (
)
var _ = Describe("odo docker devfile url command tests", func() {
- var projectDirPath, context, currentWorkingDirectory, cmpName string
- var projectDir = "/projectDir"
+ var context, currentWorkingDirectory, cmpName string
dockerClient := helper.NewDockerRunner("docker")
// This is run after every Spec (It)
@@ -22,7 +21,6 @@ var _ = Describe("odo docker devfile url command tests", func() {
SetDefaultEventuallyTimeout(10 * time.Minute)
context = helper.CreateNewContext()
currentWorkingDirectory = helper.Getwd()
- projectDirPath = context + projectDir
cmpName = helper.RandString(6)
helper.Chdir(context)
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
@@ -45,10 +43,11 @@ var _ = Describe("odo docker devfile url command tests", func() {
Context("Creating urls", func() {
It("create should pass", func() {
var stdout string
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
stdout = helper.CmdShouldPass("odo", "url", "create")
helper.MatchAllInOutput(stdout, []string{cmpName + "-3000", "created for component"})
stdout = helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
@@ -58,10 +57,12 @@ var _ = Describe("odo docker devfile url command tests", func() {
It("create with now flag should pass", func() {
var stdout string
url1 := helper.RandString(5)
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
stdout = helper.CmdShouldPass("odo", "url", "create", url1, "--now")
helper.MatchAllInOutput(stdout, []string{url1, "created for component", "Changes successfully pushed to component"})
})
@@ -69,10 +70,12 @@ var _ = Describe("odo docker devfile url command tests", func() {
It("create with same url name should fail", func() {
var stdout string
url1 := helper.RandString(5)
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "url", "create", url1)
stdout = helper.CmdShouldFail("odo", "url", "create", url1)
@@ -81,11 +84,11 @@ var _ = Describe("odo docker devfile url command tests", func() {
})
It("should be able to do a GET on the URL after a successful push", func() {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "url", "create", cmpName)
output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml")
@@ -100,10 +103,12 @@ var _ = Describe("odo docker devfile url command tests", func() {
Context("Switching pushtarget", func() {
It("switch from docker to kube, odo push should display warning", func() {
var stdout string
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "url", "create")
helper.CmdShouldPass("odo", "preference", "set", "pushtarget", "kube", "-f")
@@ -116,10 +121,12 @@ var _ = Describe("odo docker devfile url command tests", func() {
It("switch from kube to docker, odo push should display warning", func() {
var stdout string
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
helper.CmdShouldPass("odo", "preference", "set", "pushtarget", "kube", "-f")
helper.CmdShouldPass("odo", "create", "nodejs", cmpName)
+
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml"))
+
helper.CmdShouldPass("odo", "url", "create", "--host", "1.2.3.4.com", "--ingress")
helper.CmdShouldPass("odo", "preference", "set", "pushtarget", "docker", "-f")
diff --git a/tests/integration/devfile/utils/utils.go b/tests/integration/devfile/utils/utils.go
index 68950b780a4..8aa0aff94b6 100644
--- a/tests/integration/devfile/utils/utils.go
+++ b/tests/integration/devfile/utils/utils.go
@@ -19,13 +19,13 @@ func useProjectIfAvailable(args []string, project string) []string {
// ExecDefaultDevfileCommands executes the default devfile commands
func ExecDefaultDevfileCommands(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/maysunfaisal/springboot.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "java-spring-boot", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
+ helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "springboot", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
+
args = []string{"push", "--devfile", "devfile.yaml"}
args = useProjectIfAvailable(args, namespace)
output := helper.CmdShouldPass("odo", args...)
@@ -35,13 +35,11 @@ func ExecDefaultDevfileCommands(projectDirPath, cmpName, namespace string) {
// ExecWithMissingBuildCommand executes odo push with a missing build command
func ExecWithMissingBuildCommand(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-without-devbuild.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
args = []string{"push", "--devfile", "devfile.yaml"}
@@ -53,14 +51,12 @@ func ExecWithMissingBuildCommand(projectDirPath, cmpName, namespace string) {
// ExecWithMissingRunCommand executes odo push with a missing run command
func ExecWithMissingRunCommand(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
// Rename the devrun command
helper.ReplaceString(filepath.Join(projectDirPath, "devfile.yaml"), "devrun", "randomcommand")
@@ -74,14 +70,12 @@ func ExecWithMissingRunCommand(projectDirPath, cmpName, namespace string) {
// ExecWithCustomCommand executes odo push with a custom command
func ExecWithCustomCommand(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
args = []string{"push", "--devfile", "devfile.yaml", "--build-command", "build", "--run-command", "run"}
args = useProjectIfAvailable(args, namespace)
@@ -94,14 +88,12 @@ func ExecWithCustomCommand(projectDirPath, cmpName, namespace string) {
func ExecWithWrongCustomCommand(projectDirPath, cmpName, namespace string) {
garbageCommand := "buildgarbage"
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
args = []string{"push", "--devfile", "devfile.yaml", "--build-command", garbageCommand}
args = useProjectIfAvailable(args, namespace)
@@ -112,13 +104,13 @@ func ExecWithWrongCustomCommand(projectDirPath, cmpName, namespace string) {
// ExecPushToTestFileChanges executes odo push with and without a file change
func ExecPushToTestFileChanges(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
+
args = []string{"push", "--devfile", "devfile.yaml"}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
@@ -133,14 +125,12 @@ func ExecPushToTestFileChanges(projectDirPath, cmpName, namespace string) {
// ExecPushWithForceFlag executes odo push with a force flag
func ExecPushWithForceFlag(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
args = []string{"push", "--devfile", "devfile.yaml"}
args = useProjectIfAvailable(args, namespace)
@@ -155,14 +145,12 @@ func ExecPushWithForceFlag(projectDirPath, cmpName, namespace string) {
// ExecPushWithNewFileAndDir executes odo push after creating a new file and dir
func ExecPushWithNewFileAndDir(projectDirPath, cmpName, namespace, newFilePath, newDirPath string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
- helper.CopyExample(filepath.Join("source", "devfiles", "nodejs"), projectDirPath)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
+ helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
// Create a new file that we plan on deleting later...
if err := helper.CreateFileWithContent(newFilePath, "hello world"); err != nil {
@@ -180,13 +168,11 @@ func ExecPushWithNewFileAndDir(projectDirPath, cmpName, namespace, newFilePath,
// ExecWithRestartAttribute executes odo push with a command attribute restart
func ExecWithRestartAttribute(projectDirPath, cmpName, namespace string) {
- helper.CmdShouldPass("git", "clone", "https://github.com/che-samples/web-nodejs-sample.git", projectDirPath)
- helper.Chdir(projectDirPath)
-
args := []string{"create", "nodejs", cmpName}
args = useProjectIfAvailable(args, namespace)
helper.CmdShouldPass("odo", args...)
+ helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath)
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-restart.yaml"), filepath.Join(projectDirPath, "devfile.yaml"))
args = []string{"push", "--devfile", "devfile.yaml"}
diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go
index 73764d6e33b..ae9220d211c 100644
--- a/tests/integration/generic_test.go
+++ b/tests/integration/generic_test.go
@@ -80,7 +80,7 @@ var _ = Describe("odo generic", func() {
// odo project create foobar -o json
It("should be able to create project and show output in json format", func() {
actual := helper.CmdShouldPass("odo", "project", "create", projectName, "-o", "json")
- desired := fmt.Sprintf(`{"kind":"Project","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"%s","namespace":"%s","creationTimestamp":null},"message":"Project '%s' is ready for use"}`, projectName, projectName, projectName)
+ desired := fmt.Sprintf(`{"kind":"Project","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"%s","namespace":"%s","creationTimestamp":null},"message":"Project '%s' is ready for use"}`, projectName, projectName, projectName)
Expect(desired).Should(MatchJSON(actual))
})
})
@@ -97,7 +97,7 @@ var _ = Describe("odo generic", func() {
It("should fail along with proper machine readable output", func() {
helper.CmdShouldPass("odo", "project", "create", projectName)
actual := helper.CmdShouldFail("odo", "project", "create", projectName, "-o", "json")
- desired := fmt.Sprintf(`{"kind":"Error","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"creationTimestamp":null},"message":"unable to create new project: unable to create new project %s: project.project.openshift.io \"%s\" already exists"}`, projectName, projectName)
+ desired := fmt.Sprintf(`{"kind":"Error","apiVersion":"odo.dev/v1alpha1","metadata":{"creationTimestamp":null},"message":"unable to create new project: unable to create new project %s: project.project.openshift.io \"%s\" already exists"}`, projectName, projectName)
Expect(desired).Should(MatchJSON(actual))
})
})
@@ -113,7 +113,7 @@ var _ = Describe("odo generic", func() {
helper.CmdShouldPass("odo", "project", "create", projectName, "-o", "json")
actual := helper.CmdShouldPass("odo", "project", "delete", projectName, "-o", "json")
- desired := fmt.Sprintf(`{"kind":"Project","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"%s","namespace":"%s","creationTimestamp":null},"message":"Deleted project : %s"}`, projectName, projectName, projectName)
+ desired := fmt.Sprintf(`{"kind":"Project","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"%s","namespace":"%s","creationTimestamp":null},"message":"Deleted project : %s"}`, projectName, projectName, projectName)
Expect(desired).Should(MatchJSON(actual))
})
})
@@ -132,7 +132,7 @@ var _ = Describe("odo generic", func() {
})
It("should be able to return project list", func() {
actualProjectListJSON := helper.CmdShouldPass("odo", "project", "list", "-o", "json")
- partOfProjectListJSON := fmt.Sprintf(`{"kind":"Project","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"%s","creationTimestamp":null},`, project)
+ partOfProjectListJSON := fmt.Sprintf(`{"kind":"Project","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"%s","creationTimestamp":null},`, project)
Expect(actualProjectListJSON).To(ContainSubstring(partOfProjectListJSON))
})
})*/
diff --git a/tests/integration/project/cmd_project_test.go b/tests/integration/project/cmd_project_test.go
index 0e89d3c960d..8cd650492fb 100644
--- a/tests/integration/project/cmd_project_test.go
+++ b/tests/integration/project/cmd_project_test.go
@@ -57,7 +57,7 @@ var _ = Describe("odo project command tests", func() {
// project deletion doesn't happen immediately and older projects still might exist
// so we test subset of the string
- expected, err := helper.Unindented(`{"kind":"Project","apiVersion":"odo.openshift.io/v1alpha1","metadata":{"name":"` + project + `","namespace":"` + project + `","creationTimestamp":null},"spec":{},"status":{"active":true}}`)
+ expected, err := helper.Unindented(`{"kind":"Project","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"` + project + `","namespace":"` + project + `","creationTimestamp":null},"spec":{},"status":{"active":true}}`)
Expect(err).Should(BeNil())
helper.WaitForCmdOut("odo", []string{"project", "list", "-o", "json"}, 1, true, func(output string) bool {