* Autodetects framework

[Closes #87]

* use the StringTemplate template engine

Replaces the generation of config files using serialization techniques
with the use of a template engine.
Initially the idea was to use Steeltoe.Initializr however StringTemplate
turned out to be a better fit.
[closes #96]

* explicitly fail if oper not done in proper state

[closes #75]

* Update azure-pipelines.yml

* Fix test on Windows

* Disable test

* Revamp of CLI for .0.7.0-rc1 release

[Closes #64] adds 'show' command
[Closes #69] uses docker compoes to deploy app services
[Closes #74] autodetects services

Squashed commit of the following:

commit b77cbb93d2
Merge: c5f8855 ffb6429
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 08:11:23 2020 -0400

    Merge branch 'tack' of github.com:SteeltoeOSS/Tooling into tack

commit c5f8855c6a
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 08:09:22 2020 -0400

    fix url listing

commit 4f3ec442c6
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 08:05:27 2020 -0400

    add services to docker

commit 7da7963ebc
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 07:45:21 2020 -0400

    external nugets and some other rearrangements

commit 3607fd4a5a
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 07:15:14 2020 -0400

    dn not assume a particular profile

commit 90278e0dd6
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 21:55:41 2020 -0400

    add service dependency detection

commit 01e6ab7326
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 20:31:26 2020 -0400

    prep for service dependency support, part 2

commit 091203ade8
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 19:55:47 2020 -0400

    fix console assignment

commit d302207405
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 19:45:57 2020 -0400

    prep for service dependency support

commit b877e7cf96
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 19:22:31 2020 -0400

    assume a default set of services

commit a46277d004
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 17:56:47 2020 -0400

    add netcoreapp2.1

commit 0d981b6aa4
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 17:55:50 2020 -0400

    externalize image registry

commit 3d66fbe385
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 16:27:29 2020 -0400

    guess framework

commit 9fa324a198
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 15:56:16 2020 -0400

    impls stop

commit 0476ea3c78
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 15:51:08 2020 -0400

    impls run

commit 13b22b819f
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 14:41:25 2020 -0400

    prepare for running in docker

commit 93eeb1b43e
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 13:20:20 2020 -0400

    add some safety handling

commit fc5b997c51
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 12:47:37 2020 -0400

    impl show

commit 2e95c94407
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 11:22:33 2020 -0500

    update help help

commit 46511296e5
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 11:19:14 2020 -0500

    rename command show-topic to help

commit a147888d8f
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 11:12:13 2020 -0500

    impl show-topic command

commit 35a913b2a5
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 09:34:43 2020 -0500

    update show-topic help

commit aa9a7c1ad1
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 08:55:09 2020 -0500

    factor out models

commit 2854fa45ed
Author: Chris Cheetham <chris@cheetham.com>
Date:   Sun Feb 16 12:17:32 2020 -0500

    tidy

commit 9f2789bf64
Author: Chris Cheetham <chris@cheetham.com>
Date:   Sat Feb 15 12:30:19 2020 -0500

    stub new commands

commit ffb6429a02
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 08:09:22 2020 -0400

    fix url listing

commit a61d87a613
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 08:05:27 2020 -0400

    add services to docker

commit d41e137f01
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 07:45:21 2020 -0400

    external nugets and some other rearrangements

commit 430841be02
Author: Chris Cheetham <chris@cheetham.com>
Date:   Thu Mar 26 07:15:14 2020 -0400

    dn not assume a particular profile

commit 90df4ff676
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 21:55:41 2020 -0400

    add service dependency detection

commit d874e0fa22
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 20:31:26 2020 -0400

    prep for service dependency support, part 2

commit 0df0cf2f18
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 19:55:47 2020 -0400

    fix console assignment

commit 84bd775056
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 19:45:57 2020 -0400

    prep for service dependency support

commit 1170f4837d
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 19:22:31 2020 -0400

    assume a default set of services

commit aabf7dba8f
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 17:56:47 2020 -0400

    add netcoreapp2.1

commit 19d5d4745e
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 17:55:50 2020 -0400

    externalize image registry

commit bd7755410b
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 16:27:29 2020 -0400

    guess framework

commit 33ab8d9db7
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 15:56:16 2020 -0400

    impls stop

commit 7188a75bdb
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 15:51:08 2020 -0400

    impls run

commit ab75cdf8d5
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 14:41:25 2020 -0400

    prepare for running in docker

commit 5db35fdf00
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 13:20:20 2020 -0400

    add some safety handling

commit 80d3c7dd69
Author: Chris Cheetham <chris@cheetham.com>
Date:   Wed Mar 25 12:47:37 2020 -0400

    impl show

commit 454217e4aa
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 11:22:33 2020 -0500

    update help help

commit eda4ca38ee
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 11:19:14 2020 -0500

    rename command show-topic to help

commit 178d8b60ae
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 11:12:13 2020 -0500

    impl show-topic command

commit 83c66d1b90
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 09:34:43 2020 -0500

    update show-topic help

commit 9ae1542a3d
Author: Chris Cheetham <chris@cheetham.com>
Date:   Mon Feb 17 08:55:09 2020 -0500

    factor out models

commit 246f7b672e
Author: Chris Cheetham <chris@cheetham.com>
Date:   Sun Feb 16 12:17:32 2020 -0500

    tidy

commit f9fa4cd902
Author: Chris Cheetham <chris@cheetham.com>
Date:   Sat Feb 15 12:30:19 2020 -0500

    stub new commands

* Tidy

* Bump version to 0.7.0

* Allow test to pass regardless of framework

* Explicitly set framework version

* Install DotNet 3.1

* Fix pipeline indentation

* Add netcoreapp2.1 and netcoreapp3.1 support

* Install DotNet 2.1

* Doc updates

* Tidy docs

* Update README.adoc

Adding note to assist with any path issues.

* Update src/Steeltoe.Tooling/steeltoe.rc/registry/dependencies.yml

Co-authored-by: Tim Hess <thess@pivotal.io>

Co-authored-by: Tim Hess <thess@pivotal.io>
Co-authored-by: Jason Konicki <jkonicki@users.noreply.github.com>
This commit is contained in:
Chris Cheetham 2020-05-12 14:12:35 -04:00 коммит произвёл GitHub
Родитель 553eb247c6
Коммит 4b16cc1a16
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
161 изменённых файлов: 1457 добавлений и 9893 удалений

Просмотреть файл

@ -13,7 +13,7 @@ image:{uri-build-status}["Build Status", link={uri-build}]
Tools for Steeltoe Developers.
The goal of this project is to provide tools to assist Steeltoe Developers.
The current focus is an API and CLI to help with deploying Steeltoe Applications and dependent services to Cloud Foundry and Docker.
The current focus is an API and CLI to help with deploying Steeltoe Applications locally to Docker.
Subsequent goals include:
@ -21,94 +21,21 @@ Subsequent goals include:
* plugins for other IDES, such as Visual Studio Code and JetBrains Riser
* Visual Studio/DotNET templates
== Quick Start
== Install
In this Quick Start, you'll install the Steeloe Tooling CLI and use it to deploy a sample SteeltoeOSS project to Docker.
.install Steeltoe Tooling CLI and check version
.Install Steeltoe Tooling CLI and check version
----
$ dotnet tool install --global --version 1.0.0-m1 Steeltoe.Cli
$ dotnet tool install -g Steeltoe.Cli --version 0.7.0-1904 --add-source https://www.myget.org/F/steeltoedev/api/v3/index.json
You can invoke the tool using the following command: st
Tool 'steeltoe.cli' (version '0.7.0-1904') was successfully installed.
# NOTE: The dotnet tool option requires adding the tools path to the PATH variable in your environment.
# This must be done before the next step.
$ st --version
1.0.0-m1
0.7.0 (build 1904 -> https://dev.azure.com/SteeltoeOSS/Steeltoe/_build/results?buildId=1904)
----
.checkout Steeltoe Samples and navigate to the SimpleCloudFoundry project
----
$ git clone https://github.com/SteeltoeOSS/Samples.git
$ cd Samples/Configuration/src/AspDotNetCore/SimpleCloudFoundry
----
== Further Instructions for Using Steeltoe Tooling CLI
.add Steeltoe Tooling to project
----
$ st init
Initialized Steeltoe Developer Tools
----
.add application and config-server to deployment configuration
----
$ st add config-server myConfigServer
Added config-server service 'myConfigServer'
$ st add app SimpleCloudFoundry
Added app 'SimpleCloudFoundry'
----
.target Docker for deployment
----
$ st target docker
Docker ... Docker version 18.09.1, build 4c52b90
Docker host OS ... Docker for Mac
Docker container OS ... linux
Target set to 'docker'
----
.deploy
----
$ st deploy
Deploying service 'myConfigServer'
Deploying app 'SimpleCloudFoundry'
----
.check status, then navigate to application
----
$ st status
myConfigServer online
SimpleCloudFoundry online
----
Open http://localhost:8080/
.undeploy
----
$ st undeploy
Undeploying app 'SimpleCloudFoundry'
Undeploying service 'myConfigServer'
----
.deploy to Cloud Foundry
----
$ st target cloud-foundry
Cloud Foundry ... cf version 6.46.0+29d6257f1.2019-07-09
logged into Cloud Foundry ... yes
Target set to 'cloud-foundry'
$ st deploy
...
----
.deploy to Kubernetes
----
$ eval $(minikube docker-env) # if using minikube's Docker
$ st target kubernetes
Kubernetes ... kubectl client version 1.15, server version 1.15
current context ... minikube
Target set to 'kubernetes'
$ st deploy
...
----
== Further Reading
See link:docs/[Steeltoe Tooling Documentation] for more user and developer information.
See https://dev.steeltoe.io/docs/3/developer-tools/cli/[Steeltoe Tooling Documentation] for more user and developer information.

Просмотреть файл

@ -1,9 +1,17 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=autodetected/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=autodetection/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cfgname/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cfgs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Datastore/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=depname/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dummyos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hystrix/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Initializr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Postgre/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=postgresql/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rabbitmq/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sqlserver/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Steeltoe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=steeltoeoss/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Undeploy/@EntryIndexedValue">True</s:Boolean>

Просмотреть файл

@ -4,23 +4,29 @@ trigger:
- refs/tags/*
variables:
- group: '.NET Foundation'
- name: Solution
value: 'Tooling'
- name: ProductVersion
value: '0.5.0'
- name: PackageVersion
value: $[format('0.5.0-{0}', variables['Build.BuildId'])]
- name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE
value: true
- name: DOTNET_CLI_TELEMETRY_OPTOUT
value: 1
Solution: 'Tooling'
ProductVersion: '0.7.0'
PackageVersion: $[format('0.7.0-{0}', variables['Build.BuildId'])]
DotNet2Version: 2.1.x
DotNet3Version: 3.1.x
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: 1
jobs:
- job: 'Linux'
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: UseDotNet@2
displayName: 'Setup DotNet2 $(DotNet2Version)'
inputs:
packageType: sdk
version: $(DotNet2Version)
- task: UseDotNet@2
displayName: 'Setup DotNet3 $(DotNet3Version)'
inputs:
packageType: sdk
version: $(DotNet3Version)
- task: 'DotNetCoreCLI@2'
displayName: 'Build'
inputs:
@ -36,6 +42,16 @@ jobs:
pool:
vmImage: 'macOS-10.14'
steps:
- task: UseDotNet@2
displayName: 'Setup DotNet2 $(DotNet2Version)'
inputs:
packageType: sdk
version: $(DotNet2Version)
- task: UseDotNet@2
displayName: 'Setup DotNet3 $(DotNet3Version)'
inputs:
packageType: sdk
version: $(DotNet3Version)
- task: 'DotNetCoreCLI@2'
displayName: 'Build'
inputs:
@ -66,6 +82,16 @@ jobs:
env:
PackageVersion: $(PackageVersion)
displayName: 'Version'
- task: UseDotNet@2
displayName: 'Setup DotNet2 $(DotNet2Version)'
inputs:
packageType: sdk
version: $(DotNet2Version)
- task: UseDotNet@2
displayName: 'Setup DotNet3 $(DotNet3Version)'
inputs:
packageType: sdk
version: $(DotNet3Version)
- task: 'DotNetCoreCLI@2'
displayName: 'Build'
inputs:

Просмотреть файл

@ -4,6 +4,7 @@
<McMasterExtensionsCommandLineUtilsVersion>2.2.5</McMasterExtensionsCommandLineUtilsVersion>
<MicrosoftExtensionsVersion>2.1.1</MicrosoftExtensionsVersion>
<ShouldlyVersion>3.0.0</ShouldlyVersion>
<StringTemplate4Version>4.0.8</StringTemplate4Version>
<TestSdkVersion>15.7.2</TestSdkVersion>
<XunitStudioVersion>2.3.1</XunitStudioVersion>
<XunitVersion>2.3.1</XunitVersion>

Просмотреть файл

@ -1,12 +0,0 @@
= Steeltoe Tooling Documentation
:toc:
:toclevels: 3
== Developers
link:theory_of_operations.adoc[Theory of Operations]:: key Steeltoe Tooling implementation concepts
link:build.adoc[Building]:: building, testing, and installing Steeltoe Tooling from source
== Users
link:users_guide.adoc[Users Guide]:: Users guide to using Steeltoe Tooling

Просмотреть файл

@ -1,23 +0,0 @@
= Building Steeltoe Tooling
.build
----
$ dotnet build
----
.run unit and CLI tests
----
$ dotnet test test/Steeltoe.Tooling.Test
$ dotnet test test/Steeltoe.CLI.Test
----
.install
----
$ dotnet pack
$ dotnet tool install -g --add-source src/Steeltoe.Cli/bin/Debug Steeltoe.Cli
----
.uninstall
----
$ dotnet tool uninstall -g Steeltoe.Cli
----

Просмотреть файл

@ -1,75 +0,0 @@
= Steeltoe Tooling: Theory of Operations
How to setup and run the sample tests.
:uri-api-src: ../src/Steeltoe.Tooling
:uri-cli-src: ../src/Steeltoe.Cli
:toc:
== Overview
Steeltoe Tooling is comprised of 3 layers:
API:: Tooling operations and workflows
UI:: Interface with which users interact; sits on top of the API
Drivers:: Orchestrates application and service deployment; used by the API
== Components
=== API
The Steeltoe Tooling API provides a programmatic interface into Tooling functionality.
The API defines link:{uri-api-src}/Executor[workflow abstractions] intended to be used by UIs.
The API also defines the object model to be used in creating additional workflow abstractions, or as an integration point in cases where the available workflow abstractions are not sufficient.
=== UIs
The only current user interface is the link:{uri-cli-src}[Steeltoe CLI].
Future UIs may include extensions to Visual Studio and JetBrains Rider.
A UI's job is to be a bridge between a UI, such as a CLI or IDE, and the Steeltoe API (and in particular, Steeltoe API workflows).
=== Drivers
Integration with deployment targets is achieved using implementations of an link:{uri-api-src}/IDriver.cs[IDriver.cs]. A driver's job is relatively simple in scope: deploy and undeploy applications and services, and report lifecycle states of those applications and services.
== Key Concepts
=== Registry
link:{uri-api-src}/Registry.cs[Registry.cs] defines services available to Steeltoe Tooling.
Service definitions include basic information about a service, such as the service name and port.
The registry also defines services in the context of a driver. E.g., for the Docker driver, the service definition includes the Docker image name.
The service definitions are loaded from the configuration file link:{uri-api-src}/steeltoe.rc/registry.yaml[registry.yaml].
=== Lifecycles
The Steeltoe API implements a link:{uri-api-src}/Lifecycle.cs[Lifecycle.cs] of applications and services largely independent of drivers.
A driver's participation in lifecycle management is solely the determination of an application's or service's current lifecycle state.
Lifecycle transitions may or may not be permitted depending on a lifecycle state.
E.g., an application in an _Offline_ state may be deployed whereas an application in a _Starting_ state may not.
.States
Offline:: an item is not deployed
Starting:: an item is in the process of being deployed and is not yet available for use
Online:: an item is fully deployed and available for use
Stopping:: an item is in the process of being undeployed is not available for use
Unknown:: a failsafe for drivers when unable to determine an item's state
.Transitions
Deploy:: deploy an offline item
Undeploy:: undeploy an online item
=== Context
All workflows are executed in an instance of a link:{uri-api-src}/Context.cs[Context.cs] that is constructed prior to execution of the workflow. The context provides:
* path to project directory
* project configuration
* a console to which output maybe displayed to a UI
* a shell in which commands, such as driver implementation commands, may be run
* the current deployment target

Просмотреть файл

@ -1,406 +0,0 @@
= Steeltoe Tooling Users Guide
:toc:
:toclevels: 4
== CLI
=== Installing
.install
----
$ dotnet tool install --global --version 1.0.0-m1 Steeltoe.Cli
$ st --version
1.0.0-m1
----
.uninstall
----
$ dotnet tool uninstall --global steeltoe.cli
----
=== Quickstart
==== Deploy to Docker
.checkout Steeltoe Samples and navigate to the Simple project
----
$ git clone https://github.com/SteeltoeOSS/Samples.git
$ cd Samples/Configuration/src/AspDotNetCore/Simple
----
.add Steeltoe Tooling to project
----
$ st init
Initialized Steeltoe Developer Tools
----
.add application and config-server to deployment configuration
----
$ st add app simple
Added app 'simple'
$ st add config-server the-config-server
Added config-server service 'the-config-server'
----
.target Docker for deployment
----
$ st target docker
Docker ... Docker version 18.09.1, build 4c52b90
Docker host OS ... Docker for Mac
Docker container OS ... linux
Target set to 'docker'
----
.deploy
----
$ st deploy
Deploying service 'the-config-server'
Deploying app 'simple'
----
.check status, then navigate to application
----
st status
the-config-server online
simple online
----
Open http://localhost:8080/
.undeploy
----
$ st undeploy
Undeploying app 'simple'
Undeploying service 'the-config-server'
----
==== Deploy to Cloud Foundry
.checkout Steeltoe Samples and navigate to the SimpleCloudFoundry project
----
$ git clone https://github.com/SteeltoeOSS/Samples.git
$ cd Samples/Configuration/src/AspDotNetCore/SimpleCloudFoundry
----
.add Steeltoe Tooling to project
----
$ st init
Initialized Steeltoe Developer Tools
----
.add application and config-server to deployment configuration
----
$ st add app simple-cloud-foundry
Added app 'simple-cloud-foundry'
$ st add config-server the-config-server
Added config-server service 'the-config-server'
----
.target CloudFoundry for deployment
----
$ st target cloud-foundry
Cloud Foundry ... cf version 6.42.0+0cba12168.2019-01-10
logged into Cloud Foundry ... yes
Target set to 'cloud-foundry'
----
.deploy
----
$ st deploy
Deploying service 'the-config-server'
Waiting for service 'the-config-server' to come online (1)
Waiting for service 'the-config-server' to come online (2)
Waiting for service 'the-config-server' to come online (3)
...
Waiting for service 'the-config-server' to come online (35)
Deploying app 'simple-cloud-foundry'
----
.check status, then navigate to application
----
$ st status
the-config-server online
simple-cloud-foundry online
$ cf apps
Getting apps in org pivot-ccheetham / space playground as ccheetham@pivotal.io...
OK
name requested state instances memory disk urls
simple-cloud-foundry started 1/1 512M 1G simple-cloud-foundry...
^
# /
# go to this url -------------------------------------------------/
#
----
.undeploy
----
$ st undeploy
Undeploying app 'simple-cloud-foundry'
Undeploying service 'the-config-server'
----
==== Deploy to Kubernetes
.checkout Steeltoe Samples and navigate to the RabbitMQ project
----
$ git clone https://github.com/SteeltoeOSS/Samples.git
$ cd Samples/Connectors/src/AspDotNetCore/RabbitMQ
----
.add Steeltoe Tooling to project
----
$ st init
Initialized Steeltoe Developer Tools
----
.add application and config-server to deployment configuration
----
$ st add app rabbitmq-connector
Added app 'rabbitmq-connector'
$ st add rabbitmq myRabbitMQService
Added rabbitmq service 'myRabbitMQService'
----
.target Kubernetes for deployment
----
$ st target kubernetes
Kubernetes ... kubectl client version 1.14, server version 1.14
current context ... docker-desktop
Target set to 'kubernetes'
----
.deploy
----
$ st deploy
Deploying service 'myRabbitMQService'
Deploying app 'rabbitmq-connector'
----
.check status, then navigate to application
----
$ st status
myRabbitMQService online
rabbitmq-connector online
----
.undeploy
----
$ st undeploy
Undeploying app 'rabbitmq-connector'
Undeploying service 'myRabbitMQService'
----
== Services
=== Overview
A _service_ is an application that provides a capability (such as data storage) over a network protocol.
.Adding a service using the CLI command:
----
$ st add <type> <name>
----
Where _type_ is a known service type and _name_ is a user-supplied name.
.Service Types
|===
| Type | Description
| config-server | Spring Cloud Config Server
| eureka-server | Netflix Eureka Server
| hystrix-dashboard | Netflix Hystrix Dashboard
| mssql | Microsoft SQL Server
| mysql | MySQL Server
| postgresql | PostgreSQL Server
| redis | Redis Server
| zipkin | Zipkin Tracing Collector and UI
|===
=== Spring Cloud Config Server
https://spring.io/projects/spring-cloud-config[Spring Cloud Config] provides support for externalized configuration.
type:: `config-server`
port:: 8888
.Example
----
$ st add config-server myConfigServer
----
=== Netflix Eureka Server
https://github.com/Netflix/eureka/wiki[Netflix Eureka Server] provides service discovery.
type:: `eureka-server`
port:: 8761
.Example
----
$ st add eureka-server myDiscoveryServer
----
=== Hystrix Dashboard
https://github.com/Netflix/Hystrix/wiki[Hystrix Dashboard] provides latency and fault tolerance.
type:: `hystrix-dashboard`
port:: 8761
.Example
----
$ st add hystrix-dashboard myHystrixDashboard
----
=== Microsoft SQL Server
https://www.microsoft.com/sql-server/[Microsoft SQL Server] provides Microsoft's RDBMS.
type:: `mssql`
port:: 1433
.Example
----
$ st add mssql mySQLServer
----
The SteeltoeOSS Microsoft SQL Docker images (`steeltoeoss/mssql`) require explicit acceptance of the Microsoft EULA.
Acceptance can be specified using a service argument.
.Example accepting EULA in Docker images
----
$ st args -t docker mySQLServer -- --env ACCEPT_EULA=Y
----
=== MySQL Server
https://www.mysql.com/[MySQL] provides the MySQL RDBMS.
type:: `mysql`
port:: 3306
.Example
----
$ st add mysql myMySQLServer
----
The MySQL Docker images (`steeltoeoss/mssql`) for Linux containers require a MySQL root password to be set.
.Example setting MySQL root password for Linux Docker containers
----
$ st args -t docker myMySQLServer -- --env MYSQL_ROOT_PASSWORD=my-secret-pw
----
=== PostgreSQL Server
https://www.postgresql.org//[PostgreSQL] provides the PostgreSQL RDBMS.
type:: `postgresql`
port:: 5432
.Example
----
$ st add postgresql myPGServer
----
Running PostgreSQL on Cloud Foundry requires additional configuration specifying database name and user details.
.Example specifying Cloud Foundry PostgreSQL database configuration
----
$ st args -t cloud-foundry myPGServer -- -c \{\"db_name\":\"mydb\",\"db_username\":\"myuser\",\"owner_name\":\"myowner\",\"owner_email\":\"myowner@example.com\"\}
----
=== Redis Server
https://redis.io/[Redis] provides an in-memory data structure store.
type:: `redis`
port:: 6379
.Example
----
$ st add redis myRedis
----
=== Zipkin Tracing Collector and UI
https://zipkin.io/[Zipkin] provides a distributed tracing system.
type:: `zipkin`
port:: 9411
.Example
----
$ st add zipkin myZipkinCollector
----
== Targets
=== Overview
A _target_ is a deployment environment into which applications and services can be run.
.Setting the deployment target using the CLI:
----
$ st target <target>
----
Where _target_ is a known deployment target.
.Deployment Targets
|===
| Target | Description
| `cloud-foundry` | Cloud Foundry
| `docker` | Docker
|===
=== Cloud Foundry
Pre-requisistes for using Cloud Foundry as a target:
* https://docs.cloudfoundry.org/cf-cli/install-go-cli.html[Cloud Foundry CLI] (`cf` command)
* an account on a Cloud Foundry instance (or derivative such as Pivotal Cloud Foundry)
.Setting Cloud Foundry as the deployment target using the CLI:
----
$ st target cloud-foundry
Cloud Foundry ... cf version 6.42.0+0cba12168.2019-01-10
logged into Cloud Foundry ... yes
Target set to 'cloud-foundry'
----
It is assumed that you are are logged into your Cloud Foundry instance and have selected an _org_ and a _target_.
E.g., running `cf target` should look something like:
----
$ cf target
api endpoint: https://api.my.cloud.foundry.instance/
api version: 2.98.0
user: myuser
org: myorg
space: myspace
----
=== Docker
Pre-requisistes for using Docker as a target:
* https://docs.docker.com/install/[Docker] installed and running
.Setting Docker as the deployment target using the CLI:
----
$ st target docker
Docker ... Docker version 18.09.1, build 4c52b90
Docker host OS ... Docker for Mac
Docker container OS ... linux
Target set to 'docker'
----

Просмотреть файл

@ -1,45 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.ComponentModel.DataAnnotations;
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
namespace Steeltoe.Cli
{
[Command(Description = "Add an app")]
public class AddAppCommand : Command
{
public const string Name = "add-app";
[Required(ErrorMessage = "App name not specified")]
[Argument(1, Name = "name", Description = "App name")]
private string AppName { get; } = null;
[Option("-f|--framework", Description = "Target framework")]
private string Framework { get; } = "netcoreapp2.1";
[Option("-r|--runtime", Description = "Target runtime")]
private string Runtime { get; } = "win10-x64";
public AddAppCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new AddAppExecutor(AppName, Framework, Runtime);
}
}
}

Просмотреть файл

@ -1,43 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.ComponentModel.DataAnnotations;
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
namespace Steeltoe.Cli
{
[Command(Description = "Add a service")]
public class AddServiceCommand : Command
{
public const string Name = "add-service";
[Required(ErrorMessage = "Service type not specified")]
[Argument(0, Name = "type", Description = "Service type")]
private string ServiceType { get; } = null;
[Required(ErrorMessage = "Service name not specified")]
[Argument(1, Name = "name", Description = "Service name")]
private string ServiceName { get; } = null;
public AddServiceCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new AddServiceExecutor(ServiceName, ServiceType);
}
}
}

Просмотреть файл

@ -1,74 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
// ReSharper disable UnassignedGetOnlyAutoProperty
namespace Steeltoe.Cli
{
[Command(
Description = "Set or get the arguments for an app or service",
ExtendedHelpText =
"If run with no arguments, show the current arguments for the app or service.",
AllowArgumentSeparator = true
)]
public class ArgsCommand : Command
{
public const string Name = "args";
[Required(ErrorMessage = "App or service name not specified")]
[Argument(0, Name = "name", Description = "App or service name")]
private string AppOrServiceName { get; }
[Argument(2, Name = "args", Description = "App or service arguments")]
private List<string> Arguments { get; }
[Option("-t|--target", Description = "Apply the args to the deployment on the specified target")]
private string Target { get; }
[Option("-F|--force", Description = "Overwrite existing arguments")]
private bool Force { get; }
private List<string> RemainingArguments { get; }
public ArgsCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
var args = new List<string>();
if (Arguments != null)
{
args.AddRange(Arguments);
}
if (RemainingArguments != null)
{
args.AddRange(RemainingArguments);
}
if (args.Count == 0)
{
return new GetArgsExecutor(AppOrServiceName, Target);
}
return new SetArgsExecutor(AppOrServiceName, Target, string.Join(" ", args), Force);
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -13,10 +13,12 @@
// limitations under the License.
using System;
using System.IO;
using System.Reflection;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using Steeltoe.Tooling;
using Steeltoe.Tooling.Executors;
using Steeltoe.Tooling.Controllers;
namespace Steeltoe.Cli
{
@ -35,29 +37,18 @@ namespace Steeltoe.Cli
{
try
{
Logger.LogDebug($"tooling working directory: {app.WorkingDirectory}");
var cfgFilePath = Program.ProjectConfigurationPath ?? app.WorkingDirectory;
Configuration cfg;
var cfgFile = new ConfigurationFile(cfgFilePath);
if (cfgFile.Exists())
Logger.LogDebug($"working directory: {app.WorkingDirectory}");
var context = new Context
{
cfg = cfgFile.Configuration;
Logger.LogDebug($"tooling configuration file: {cfgFile.File}");
}
else
{
cfg = null;
Logger.LogDebug($"tooling configuration file not found: {cfgFile.File}");
}
var context = new Context(
app.WorkingDirectory,
cfg,
_console.Out,
new CommandShell()
);
GetExecutor().Execute(context);
WorkingDirectory = app.WorkingDirectory,
Console = _console.Out,
Shell = new CommandShell(),
Registry = new Registry()
};
context.Registry.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"steeltoe.rc",
"registry"));
GetController().Execute(context);
return 0;
}
catch (ArgumentException e)
@ -86,6 +77,6 @@ namespace Steeltoe.Cli
}
}
protected abstract Executor GetExecutor();
protected abstract Controller GetController();
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -87,7 +87,6 @@ namespace Steeltoe.Cli
private static void OutputToConsole(string output)
{
if (!Settings.VerboseEnabled) return;
var oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Out.WriteLine(output);

Просмотреть файл

@ -1,34 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
namespace Steeltoe.Cli
{
[Command(Description = "Deploy apps and services to the target")]
public class DeployCommand : Command
{
public const string Name = "deploy";
public DeployCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new DeployExecutor();
}
}
}

Просмотреть файл

@ -1,72 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling;
using Steeltoe.Tooling.Executors;
namespace Steeltoe.Cli
{
[Command(Description = "Check for potential problems")]
public class DoctorCommand : Command
{
public const string Name = "doctor";
public DoctorCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new DoctorExecutor();
}
}
internal class DoctorExecutor : Executor
{
protected override void Execute()
{
Context.Console.WriteLine($"Steeltoe Developer Tools version ... {Program.GetVersion()}");
// dotnet
Context.Console.Write("DotNet ... ");
var dotnetVersion = new Tooling.Cli("dotnet", Context.Shell).Run("--version", "getting dotnet version")
.Trim();
Context.Console.WriteLine($"dotnet version {dotnetVersion}");
// is intialized?
Context.Console.Write("initialized ... ");
var cfgFile = new ConfigurationFile(Context.ProjectDirectory);
if (!cfgFile.Exists())
{
Context.Console.WriteLine($"!!! no (run '{Program.Name} {InitCommand.Name}' to initialize)");
return;
}
Context.Console.WriteLine("yes");
// target deployment environment
Context.Console.Write("target ... ");
string target = cfgFile.Configuration.Target;
if (target == null)
{
Context.Console.WriteLine($"!!! not set (run '{Program.Name} {TargetCommand.Name} <env>' to set)");
return;
}
Context.Console.WriteLine(target);
Registry.GetTarget(target).IsHealthy(Context);
}
}
}

Просмотреть файл

@ -0,0 +1,119 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
using System.Linq;
using System.Reflection;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using Steeltoe.Tooling;
using Steeltoe.Tooling.Controllers;
namespace Steeltoe.Cli
{
[Command(Description = "Displays documentation on a topic",
ExtendedHelpText = @"
Overview:
Displays documentation for various topics. Run with no arguments for a list of available topics.
Examples:
Display documentation topics:
$ st help
Display documentation for autodetection:
$ st help autodetection"
)]
public class HelpCommand : Command
{
public const string CommandName = "help";
[Argument(0, Name = "topic", Description = "Topic")]
private string Topic { get; } = null;
public HelpCommand(IConsole console) : base(console)
{
}
protected override Controller GetController()
{
return new ShowTopicController(Topic);
}
private class ShowTopicController : Controller
{
private static readonly ILogger<ShowTopicController> Logger =
Logging.LoggerFactory.CreateLogger<ShowTopicController>();
private readonly string _topicsPath = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"steeltoe.rc",
"topics");
private readonly string _topic;
public ShowTopicController(string topic)
{
_topic = topic;
}
protected override void Execute()
{
Logger.LogDebug($"topics path: {_topicsPath}");
if (_topic == null)
{
ListTopics();
}
else
{
ShowTopic(_topic);
}
}
private void ListTopics()
{
var topicPaths = Directory.GetFiles(_topicsPath, "*.txt");
var maxTopicLength = topicPaths.Select(Path.GetFileNameWithoutExtension)
.Select(topic => topic.Length).Concat(new[] {0}).Max();
var descriptionColumn = maxTopicLength + 4;
foreach (var topicPath in topicPaths)
{
var topic = Path.GetFileNameWithoutExtension(topicPath);
var description = File.ReadLines(topicPath).First();
Context.Console.WriteLine($"{topic.PadRight(descriptionColumn)}{description}");
}
}
private void ShowTopic(string topic)
{
var topicPath = Path.Combine(_topicsPath, $"{topic}.txt");
if (!File.Exists(topicPath))
{
throw new TopicDoesNotExistException(topic);
}
foreach (var line in File.ReadLines(topicPath))
{
Context.Console.WriteLine(line);
}
}
class TopicDoesNotExistException : ToolingException
{
public TopicDoesNotExistException(string topic) : base($"Topic does not exist: {topic}")
{
}
}
}
}
}

Просмотреть файл

@ -1,42 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
// ReSharper disable UnassignedGetOnlyAutoProperty
namespace Steeltoe.Cli
{
[Command(Description = "Initialize Steeltoe Developer Tools")]
public class InitCommand : Command
{
public const string Name = "init";
[Option("-a|--autodetect", Description = "Autodetect application")]
private bool Autodetect { get; }
[Option("-F|--force", Description = "Initialize the project even if already initialized")]
private bool Force { get; }
public InitCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new InitializationExecutor(Program.ProjectConfigurationPath, autodetect: Autodetect, force: Force);
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -20,17 +20,10 @@ namespace Steeltoe.Cli
{
[Command(Name = Name, Description = "Steeltoe Developer Tools")]
[VersionOptionFromMember("-V|--version", MemberName = nameof(GetVersion))]
[Subcommand(InitCommand.Name, typeof(InitCommand))]
[Subcommand(TargetCommand.Name, typeof(TargetCommand))]
[Subcommand(AddAppCommand.Name, typeof(AddAppCommand))]
[Subcommand(AddServiceCommand.Name, typeof(AddServiceCommand))]
[Subcommand(RemoveCommand.Name, typeof(RemoveCommand))]
[Subcommand(DeployCommand.Name, typeof(DeployCommand))]
[Subcommand(UndeployCommand.Name, typeof(UndeployCommand))]
[Subcommand(StatusCommand.Name, typeof(StatusCommand))]
[Subcommand(ArgsCommand.Name, typeof(ArgsCommand))]
[Subcommand(ListCommand.Name, typeof(ListCommand))]
[Subcommand(DoctorCommand.Name, typeof(DoctorCommand))]
[Subcommand(HelpCommand.CommandName, typeof(HelpCommand))]
[Subcommand(RunCommand.CommandName, typeof(RunCommand))]
[Subcommand(ShowCommand.CommandName, typeof(ShowCommand))]
[Subcommand(StopCommand.CommandName, typeof(StopCommand))]
public class Program
{
public const string Name = "st";
@ -48,11 +41,6 @@ namespace Steeltoe.Cli
$"{version} (build {build} -> https://dev.azure.com/SteeltoeOSS/Steeltoe/_build/results?buildId={build})";
}
[Option("-C|--config-file", Description =
"Configure tooling using the specified file instead of steeltoe.yaml")]
// ReSharper disable once UnassignedGetOnlyAutoProperty
public static string ProjectConfigurationPath { get; }
[Option("-D|--debug", Description = "Enable debug output")]
public static bool DebugEnabled
{
@ -60,13 +48,6 @@ namespace Steeltoe.Cli
set => Settings.DebugEnabled = value;
}
[Option("-v|--verbose", Description = "Enable verbose output")]
public static bool VerboseEnabled
{
get => Settings.VerboseEnabled;
set => Settings.VerboseEnabled = value;
}
// ReSharper disable once UnusedMember.Local
private int OnExecute(CommandLineApplication app)
{

Просмотреть файл

@ -1,41 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.ComponentModel.DataAnnotations;
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
// ReSharper disable UnassignedGetOnlyAutoProperty
namespace Steeltoe.Cli
{
[Command(Description = "Remove an app or service")]
public class RemoveCommand : Command
{
public const string Name = "remove";
[Required(ErrorMessage = "App or service name not specified")]
[Argument(0, Name = "name", Description = "App or service name")]
private string AppOrServiceName { get; }
public RemoveCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new RemoveExecutor(AppOrServiceName);
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Controllers;
namespace Steeltoe.Cli
{
[Command(Description = "Runs project in the local Docker environment",
ExtendedHelpText = @"
Overview:
Starts the project application and its dependencies in the local Docker environment.
Examples:
Run the default configuration:
$ st run
See Also:
stop")]
public class RunCommand : Command
{
public const string CommandName = "run";
[Option("-g|--generate-only", Description = "Only generate configuration files (don't run in Docker)")]
private bool GenerateOnly { get; }
public RunCommand(IConsole console) : base(console)
{
}
protected override Controller GetController()
{
return new RunController(!GenerateOnly);
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -13,27 +13,29 @@
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
// ReSharper disable UnassignedGetOnlyAutoProperty
using Steeltoe.Tooling.Controllers;
namespace Steeltoe.Cli
{
[Command(Description = "List apps and services")]
public class ListCommand : Command
[Command(Description = "Displays project details",
ExtendedHelpText = @"
Overview:
*** under construction ***
Examples:
Show the details of the project in the current directory:
$ st show")]
public class ShowCommand : Command
{
public const string Name = "list";
public const string CommandName = "show";
[Option("-v|--verbose", Description = "Verbose")]
private bool Verbose { get; }
public ListCommand(IConsole console) : base(console)
public ShowCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
protected override Controller GetController()
{
return new ListExecutor(Verbose);
return new ShowController();
}
}
}

Просмотреть файл

@ -1,34 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
namespace Steeltoe.Cli
{
[Command(Description = "Show app and service statuses")]
public class StatusCommand : Command
{
public const string Name = "status";
public StatusCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
return new StatusExecutor();
}
}
}

Просмотреть файл

@ -3,7 +3,7 @@
<PropertyGroup>
<Title>Steeltoe CLI</Title>
<Description>Commandline interface to Steeltoe Tooling</Description>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks>
<ToolCommandName>st</ToolCommandName>
<PackAsTool>true</PackAsTool>
<OutputType>exe</OutputType>

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,23 +12,34 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
using Steeltoe.Tooling.Controllers;
namespace Steeltoe.Cli
{
[Command(Description = "Undeploy apps and services from the target")]
public class UndeployCommand : Command
{
public const string Name = "undeploy";
[Command(Description = "Stops project running in the local Docker environment",
ExtendedHelpText = @"
Overview:
Stops the project application and its dependencies in the local Docker environment.
public UndeployCommand(IConsole console) : base(console)
Examples:
Stop the running project:
$ st stop
See Also:
run")]
public class StopCommand : Command
{
public const string CommandName = "stop";
public StopCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
protected override Controller GetController()
{
return new UndeployExecutor();
return new StopController();
}
}
}

Просмотреть файл

@ -1,49 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using McMaster.Extensions.CommandLineUtils;
using Steeltoe.Tooling.Executors;
// ReSharper disable UnassignedGetOnlyAutoProperty
namespace Steeltoe.Cli
{
[Command(Description =
"Set or get the deployment target",
ExtendedHelpText = "If run with no args, show the current deployment target.")]
public class TargetCommand : Command
{
public const string Name = "target";
[Argument(0, Name = "target", Description = "Deployment target name")]
private string Target { get; }
[Option("-F|--force", Description = "Set the deployment target even if checks fail")]
private bool Force { get; }
public TargetCommand(IConsole console) : base(console)
{
}
protected override Executor GetExecutor()
{
if (Target == null)
{
return new GetTargetExecutor();
}
return new SetTargetExecutor(Target, Force);
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -63,7 +63,6 @@ namespace Steeltoe.Tooling
private static void OutputToConsole(string output)
{
if (!Settings.VerboseEnabled) return;
var oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Blue;
Console.Out.WriteLine(output);

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Просмотреть файл

@ -1,418 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling
{
/// <summary>
/// Represents a configuration for a Steeltoe Tooling project.
/// </summary>
public class Configuration
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<Configuration>();
private string _target;
/// <summary>
/// Project deployment target.
/// </summary>
[YamlMember(Alias = "target")]
public string Target
{
get => _target;
set
{
_target = value;
NotifyChanged();
}
}
/// <summary>
/// Project applications.
/// </summary>
[YamlMember(Alias = "apps")]
public SortedDictionary<string, App> Apps { get; set; } = new SortedDictionary<string, App>();
/// <summary>
/// Project application services.
/// </summary>
[YamlMember(Alias = "services")]
public SortedDictionary<string, Service> Services { get; set; } = new SortedDictionary<string, Service>();
private readonly List<IConfigurationListener> _listeners = new List<IConfigurationListener>();
/// <summary>
/// Adds the named application to this configuration.
/// </summary>
/// <param name="app">Name of application to be added.</param>
/// <param name="framework">Target framework.</param>
/// <param name="runtime">Target runtime.</param>
/// <exception cref="ItemExistsException">Thrown if an application of the same name has already been added to this configuration.</exception>
public void AddApp(string app, string framework, string runtime)
{
Logger.LogDebug($"adding app {app} ({framework}/{runtime})");
if (Apps.ContainsKey(app))
{
throw new ItemExistsException(app, "app");
}
Apps[app] = new App();
Apps[app].TargetFramework = framework;
Apps[app].TargetRuntime = runtime;
NotifyChanged();
}
/// <summary>
/// Removes the named application from the configuration.
/// </summary>
/// <param name="app">Name of application to be removed.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application does not exist in this configuration.</exception>
public void RemoveApp(string app)
{
Logger.LogDebug($"removing app {app}");
if (!Apps.Remove(app))
{
throw new ItemDoesNotExistException(app, "app");
}
NotifyChanged();
}
/// <summary>
/// Returns this configuration's applications.
/// </summary>
/// <returns>This configuration's applications.</returns>
public List<string> GetApps()
{
return Apps.Keys.ToList();
}
/// <summary>
/// Returns the named application.
/// </summary>
/// <param name="app">Application name</param>
/// <returns>Named application.</returns>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application does not exist in this configuration.</exception>
public AppInfo GetAppInfo(string app)
{
if (Apps.ContainsKey(app))
{
return new AppInfo(app);
}
else
{
throw new ItemDoesNotExistException(app, "app");
}
}
/// <summary>
/// Sets the named application's arguments.
/// </summary>
/// <param name="app">Application name.</param>
/// <param name="args">Application arguments.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application does not exist in this configuration.</exception>
public void SetAppArgs(string app, string args)
{
Logger.LogDebug($"setting app '{app}' args to '{args}'");
if (!Apps.ContainsKey(app))
{
throw new ItemDoesNotExistException(app, "app");
}
Apps[app].Args = args;
NotifyChanged();
}
/// <summary>
/// Sets the named application's deployment arguments.
/// </summary>
/// <param name="app">Application name.</param>
/// <param name="target">Deployment target.</param>
/// <param name="args">Application arguments.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application does not exist in this configuration.</exception>
public void SetAppArgs(string app, string target, string args)
{
Logger.LogDebug($"setting app '{app}' args for target '{target}' to '{args}'");
if (!Registry.Targets.Contains(target))
{
throw new ItemDoesNotExistException(target, "target");
}
if (!Apps.ContainsKey(app))
{
throw new ItemDoesNotExistException(app, "app");
}
Apps[app].DeployArgs[target] = args;
NotifyChanged();
}
/// <summary>
/// Gets the named application's arguments.
/// </summary>
/// <param name="app">Application name.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application does not exist in this configuration.</exception>
public string GetAppArgs(string app)
{
try
{
return Apps[app].Args;
}
catch (KeyNotFoundException)
{
throw new ItemDoesNotExistException(app, "app");
}
}
/// <summary>
/// Gets the named application's deployment arguments.
/// </summary>
/// <param name="app">Application name.</param>
/// <param name="target">Deployment target.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application does not exist in this configuration.</exception>
public string GetAppArgs(string app, string target)
{
if (!Registry.Targets.Contains(target))
{
throw new ItemDoesNotExistException(target, "target");
}
try
{
Apps[app].DeployArgs.TryGetValue(target, out var args);
return args;
}
catch (KeyNotFoundException)
{
throw new ItemDoesNotExistException(app, "app");
}
}
/// <summary>
/// Adds the named application service to this configuration.
/// </summary>
/// <param name="service">Name of application service to be added.</param>
/// <param name="serviceType">Name of application service type.</param>
/// <exception cref="ItemExistsException">Thrown if an application service of the same name has already been added to this configuration.</exception>
public void AddService(string service, string serviceType)
{
Logger.LogDebug($"adding service {serviceType} '{service}'");
if (!Registry.GetServiceTypes().Contains(serviceType))
{
throw new ItemDoesNotExistException(serviceType, "service type");
}
if (Services.ContainsKey(service))
{
throw new ItemExistsException(service, "service");
}
Services[service] = new Service {ServiceTypeName = serviceType};
NotifyChanged();
}
/// <summary>
/// Removes the named application service from the configuration.
/// </summary>
/// <param name="service">Name of application service to be removed.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application service does not exist in this configuration.</exception>
public void RemoveService(string service)
{
Logger.LogDebug($"removing service {service}");
if (!Services.Remove(service))
{
throw new ItemDoesNotExistException(service, "service");
}
NotifyChanged();
}
/// <summary>
/// Returns this configuration's application services.
/// </summary>
/// <returns>This configuration's applications services.</returns>
public List<string> GetServices()
{
return Services.Keys.ToList();
}
/// <summary>
/// Returns the named application service.
/// </summary>
/// <param name="service">Application service name</param>
/// <returns>Named application service.</returns>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application service does not exist in this configuration.</exception>
public ServiceInfo GetServiceInfo(string service)
{
try
{
return new ServiceInfo(service, Services[service].ServiceTypeName);
}
catch (KeyNotFoundException)
{
throw new ItemDoesNotExistException(service, "service");
}
}
/// <summary>
/// Sets the named application service's arguments.
/// </summary>
/// <param name="service">Application service name.</param>
/// <param name="args">Application service arguments.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application service does not exist in this configuration.</exception>
public void SetServiceArgs(string service, string args)
{
Logger.LogDebug($"setting service '{service}' args to '{args}'");
if (!Services.ContainsKey(service))
{
throw new ItemDoesNotExistException(service, "service");
}
Services[service].Args = args;
NotifyChanged();
}
/// <summary>
/// Sets the named application services's deployment arguments.
/// </summary>
/// <param name="service">Application service name.</param>
/// <param name="target">Deployment target.</param>
/// <param name="args">Application service arguments.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application service does not exist in this configuration.</exception>
public void SetServiceArgs(string service, string target, string args)
{
Logger.LogDebug($"setting service '{service}' args for target '{target} to '{args}'");
if (!Registry.Targets.Contains(target))
{
throw new ItemDoesNotExistException(target, "target");
}
if (!Services.ContainsKey(service))
{
throw new ItemDoesNotExistException(service, "service");
}
Services[service].DeployArgs[target] = args;
NotifyChanged();
}
/// <summary>
/// Gets the named application service's arguments.
/// </summary>
/// <param name="service">Application service name.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application service does not exist in this configuration.</exception>
public string GetServiceArgs(string service)
{
try
{
return Services[service].Args;
}
catch (KeyNotFoundException)
{
throw new ItemDoesNotExistException(service, "service");
}
}
/// <summary>
/// Gets the named application service's deployment arguments.
/// </summary>
/// <param name="service">Application service name.</param>
/// <param name="target">Deployment target.</param>
/// <exception cref="ItemDoesNotExistException">Thrown if the named application service does not exist in this configuration.</exception>
public string GetServiceArgs(string service, string target)
{
if (!Registry.Targets.Contains(target))
{
throw new ItemDoesNotExistException(target, "target");
}
try
{
Services[service].DeployArgs.TryGetValue(target, out var args);
return args;
}
catch (KeyNotFoundException)
{
throw new ItemDoesNotExistException(service, "service");
}
}
/// <summary>
/// Adds a listener for configuration changes,
/// </summary>
/// <param name="listener">Listener to be notified when configuration changes.</param>
public void AddListener(IConfigurationListener listener)
{
_listeners.Add(listener);
}
/// <summary>
/// Notify all listeners that this configuration has changed.
/// </summary>
public void NotifyChanged()
{
Logger.LogDebug("configuration changed");
foreach (var listener in _listeners)
{
listener.ConfigurationChangeEvent();
}
}
/// <summary>
/// Represents an application in this configuration.
/// </summary>
public class App
{
/// <summary>
/// Application target framework.
/// </summary>
[YamlMember(Alias = "targetFramework")]
public string TargetFramework { get; set; }
/// <summary>
/// Application target runtime.
/// </summary>
[YamlMember(Alias = "targetRuntime")]
public string TargetRuntime { get; set; }
/// <summary>
/// Application arguments.
/// </summary>
[YamlMember(Alias = "args")]
public string Args { get; set; }
/// <summary>
/// Application deployment target arguments.
/// </summary>
[YamlMember(Alias = "deployArgs")]
public SortedDictionary<string, string> DeployArgs { get; set; } = new SortedDictionary<string, string>();
}
/// <summary>
/// Represents an application service in this configuration.
/// </summary>
public class Service : App
{
/// <summary>
/// Application service type.
/// </summary>
[YamlMember(Alias = "type")]
public string ServiceTypeName { get; set; }
}
}
}

Просмотреть файл

@ -1,106 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling
{
/// <summary>
/// Represents a Steeltoe Tooling project configuration file.
/// </summary>
public class ConfigurationFile : IConfigurationListener
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<ConfigurationFile>();
/// <summary>
/// Default file name.
/// </summary>
public const string DefaultFileName = "steeltoe.yaml";
/// <summary>
/// The configuration stored in this configuration file.
/// </summary>
public Configuration Configuration { get; private set; }
/// <summary>
/// Configuration file name.
/// </summary>
public string File { get; }
/// <summary>
/// Creates a new ConfigurationFile at the specified path.
/// </summary>
/// <param name="path">Configuration file path.</param>
public ConfigurationFile(string path)
{
File = Directory.Exists(path) ? Path.Combine(path, DefaultFileName) : path;
if (Exists())
{
Load();
}
else
{
Configuration = new Configuration();
}
}
/// <summary>
/// Loads this configuration file from the file system.
/// </summary>
public void Load()
{
Logger.LogDebug($"loading configuration from {File}");
var deserializer = new DeserializerBuilder().Build();
using (var reader = new StreamReader(File))
{
Configuration = deserializer.Deserialize<Configuration>(reader);
}
Configuration.AddListener(this);
}
/// <summary>
/// Loads this configuration file to the file system.
/// </summary>
public void Store()
{
Logger.LogDebug($"storing configuration to {File}");
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(Configuration);
using (var writer = new StreamWriter(File))
{
writer.Write(yaml);
}
}
/// <summary>
/// Tests if this configuration file exists on the file system.
/// </summary>
/// <returns>True is this configuration file exists.</returns>
public bool Exists()
{
return System.IO.File.Exists(File);
}
/// <summary>
/// Called when this configuration file's configuration has been changed.
/// </summary>
public void ConfigurationChangeEvent()
{
Store();
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -22,60 +22,23 @@ namespace Steeltoe.Tooling
public class Context
{
/// <summary>
/// Steeltoe Tooling project directory.
/// Steeltoe Tooling working directory.
/// </summary>
public string ProjectDirectory { get; }
/// <summary>
/// Steeltoe Tooling configuration.
/// </summary>
public Configuration Configuration { get; set; }
public string WorkingDirectory { get; set; }
/// <summary>
/// Steeltoe Tooling console. Typically the console is used to display messages to the user.
/// </summary>
public TextWriter Console { get; }
public TextWriter Console { get; set; }
/// <summary>
/// Shell which which to run system commands.
/// </summary>
public Shell Shell { get; }
public Shell Shell { get; set; }
/// <summary>
/// Steeltoe Tooling deployment target.
/// Tooling registry.
/// </summary>
/// <exception cref="ToolingException">Throw if the target has not been set.</exception>
public Target Target
{
get
{
if (Configuration?.Target == null)
{
throw new ToolingException("Target not set");
}
return Registry.GetTarget(Configuration.Target);
}
}
/// <summary>
/// Steeltoe Tooling driver. The driver is used to deploy applications and their services.
/// </summary>
public IDriver Driver => Target.GetDriver(this);
/// <summary>
/// Creates a new Steeltoe Tooling Content.
/// </summary>
/// <param name="dir">Project directory.</param>
/// <param name="config">Project configuration.{</param>
/// <param name="console">User console.</param>
/// <param name="shell">Command shell.</param>
public Context(string dir, Configuration config, TextWriter console, Shell shell)
{
ProjectDirectory = dir;
Configuration = config;
Console = console;
Shell = shell;
}
public Registry Registry { get; set; }
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,17 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Logging;
using Steeltoe.Tooling.Models;
namespace Steeltoe.Tooling.Executors
namespace Steeltoe.Tooling.Controllers
{
/// <summary>
/// Represents a Steeltoe Tooling workflow.
/// </summary>
public abstract class Executor
public abstract class Controller
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<Executor>();
/// <summary>
/// The context in which the workflow executes.
/// </summary>
@ -35,30 +33,6 @@ namespace Steeltoe.Tooling.Executors
/// <exception cref="ToolingException">If an error occurs running the workflow.</exception>
public void Execute(Context context)
{
var type = GetType();
Logger.LogDebug($"executor is {type}");
foreach (var attr in type.GetCustomAttributes(true))
{
if (attr is RequiresInitializationAttribute)
{
Logger.LogDebug($"{type} requires configuration");
if (context.Configuration == null)
{
throw new ToolingException("Steeltoe Developer Tools has not been initialized");
}
}
if (attr is RequiresTargetAttribute)
{
Logger.LogDebug($"{type} requires target");
if (context.Target == null)
{
throw new ToolingException("Target has not been set");
}
}
}
Context = context;
Execute();
}
@ -67,5 +41,14 @@ namespace Steeltoe.Tooling.Executors
/// Sub-classes implement this to perform their specific workflow.
/// </summary>
protected abstract void Execute();
/// <summary>
/// Returns the project.
/// </summary>
/// <returns>The project.</returns>
protected DeploymentConfiguration GetDeployment()
{
return new DeploymentConfigurationBuilder(Context).BuildDeployment();
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
using Microsoft.Extensions.Logging;
using Steeltoe.Tooling.Templates;
namespace Steeltoe.Tooling.Controllers
{
/// <summary>
/// Controls the "run" operation.
/// </summary>
public class RunController : Controller
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<RunController>();
private readonly bool _runInDocker;
/// <summary>
/// Runs the project in the local Docker environment.
/// </summary>
/// <param name="runInDocker"></param>
public RunController(bool runInDocker)
{
_runInDocker = runInDocker;
}
/// <summary>
/// Runs the project in the local Docker environment.
/// </summary>
protected override void Execute()
{
var deployment = GetDeployment();
if (!Context.Registry.DotnetImages.TryGetValue(deployment.Project.Framework, out var image))
{
throw new ToolingException($"no image for framework: {deployment.Project.Framework}");
}
var files = new string[] {"Dockerfile", "docker-compose.yml"};
foreach (var file in files)
{
Logger.LogDebug($"writing {file}");
var template = TemplateManager.GetTemplate($"{file}.st");
template.Bind("project", deployment.Project);
template.Bind("image", image);
File.WriteAllText(file, template.Render());
}
if (!_runInDocker) return;
var cli = new Cli("docker-compose", Context.Shell);
cli.Run("up --build", $"running '{deployment.Project.Name}' in Docker");
}
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Controllers
{
/// <summary>
/// Controls the "show" operation.
/// </summary>
public class ShowController : Controller
{
/// <summary>
/// Creates a new ShowController.
/// </summary>
public ShowController()
{
}
/// <summary>
/// Shows project details.
/// </summary>
protected override void Execute()
{
var serializer = new SerializerBuilder().Build();
Context.Console.WriteLine(serializer.Serialize(GetDeployment()));
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,20 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
namespace Steeltoe.Tooling.Controllers
{
/// <summary>
/// A workflow to display the current deployment target.
/// Controls the "stop" operation.
/// </summary>
[RequiresTarget]
public class GetTargetExecutor : Executor
public class StopController : Controller
{
/// <summary>
/// Display the current deployment target.
/// Stops the project in the local Docker environment.
/// </summary>
protected override void Execute()
{
Context.Console.WriteLine(Context.Configuration.Target);
var project = GetDeployment().Project;
var cli = new Cli("docker-compose", Context.Shell);
cli.Run("down", $"stopping '{project.Name}' in Docker");
}
}
}

Просмотреть файл

@ -1,23 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Drivers.CloudFoundry
{
internal class CloudFoundryCli : Cli
{
internal CloudFoundryCli(Shell shell) : base("cf", shell)
{
}
}
}

Просмотреть файл

@ -1,169 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.Text.RegularExpressions;
namespace Steeltoe.Tooling.Drivers.CloudFoundry
{
internal class CloudFoundryDriver : IDriver
{
private readonly Context _context;
private readonly Cli _cfCli;
private readonly Cli _dotnetCli;
internal CloudFoundryDriver(Context context)
{
_context = context;
_cfCli = new CloudFoundryCli(context.Shell);
_dotnetCli = new Cli("dotnet", _context.Shell);
}
public void DeploySetup()
{
}
public void DeployTeardown()
{
}
public void DeployApp(string app)
{
var manifestPath = Path.Combine(_context.ProjectDirectory, CloudFoundryManifestFile.DefaultFileName);
if (File.Exists(manifestPath))
{
File.Delete(manifestPath);
}
var cloudFoundryApp = new CloudFoundryManifest.Application();
cloudFoundryApp.Name = app;
cloudFoundryApp.Memory = "512M";
cloudFoundryApp.Environment = new Dictionary<string, string> {{"ASPNETCORE_ENVIRONMENT", "development"}};
cloudFoundryApp.ServiceNames = _context.Configuration.GetServices();
if (_context.Configuration.Apps[app].TargetRuntime.StartsWith("ubuntu"))
{
cloudFoundryApp.BuildPacks = new List<string> {"dotnet_core_buildpack"};
cloudFoundryApp.Command = $"cd ${{HOME}} && ./{Path.GetFileName(_context.ProjectDirectory)}";
}
else
{
cloudFoundryApp.Stack = "windows";
cloudFoundryApp.BuildPacks = new List<string> {"hwc_buildpack"};
cloudFoundryApp.Command = $"cmd /c .\\{Path.GetFileName(_context.ProjectDirectory)}";
}
var manifestFile = new CloudFoundryManifestFile(manifestPath);
manifestFile.CloudFoundryManifest.Applications.Add(cloudFoundryApp);
manifestFile.Store();
var framework = _context.Configuration.Apps[app].TargetFramework;
var runtime = _context.Configuration.Apps[app].TargetRuntime;
_dotnetCli.Run($"publish -f {framework} -r {runtime}", "publishing app");
_cfCli.Run(
$"push -f {CloudFoundryManifestFile.DefaultFileName} -p bin/Debug/{framework}/{runtime}/publish",
"pushing app to Cloud Foundry");
}
public void UndeployApp(string app)
{
_cfCli.Run($"delete {app} -f", $"deleting Cloud Foundry app");
}
public Lifecycle.Status GetAppStatus(string app)
{
try
{
var appInfo = _cfCli.Run($"app {app}", "getting details for Cloud Foundry app");
var state = new Regex(@"^#0\s+(\S+)", RegexOptions.Multiline).Match(appInfo).Groups[1].ToString()
.Trim();
switch (state)
{
case "down":
return Lifecycle.Status.Starting;
case "running":
return Lifecycle.Status.Online;
}
}
catch (CliException e)
{
if (e.Error.Contains($"App {app} not found"))
{
return Lifecycle.Status.Offline;
}
if (e.Error.Contains($"App '{app}' not found"))
{
return Lifecycle.Status.Offline;
}
}
return Lifecycle.Status.Unknown;
}
public void DeployService(string service)
{
var svcInfo = _context.Configuration.GetServiceInfo(service);
_context.Target.Configuration.ServiceTypeProperties.TryGetValue(svcInfo.ServiceType, out var cfServiceDef);
if (cfServiceDef == null)
{
throw new ToolingException($"No Cloud Foundry service available for '{svcInfo.Service}' [{svcInfo.ServiceType}]");
}
var cfCmd = $"create-service {cfServiceDef["service"]} {cfServiceDef["plan"]} {service}";
var svcArgs = _context.Configuration.GetServiceArgs(service, "cloud-foundry") ?? "";
if (svcArgs.Length > 0)
{
svcArgs = svcArgs.Replace("\"", "\"\"\"");
cfCmd += $" {svcArgs}";
}
_cfCli.Run(cfCmd, "creating Cloud Foundry service");
}
public void UndeployService(string service)
{
_cfCli.Run($"delete-service {service} -f", "deleting Cloud Foundry service");
}
public Lifecycle.Status GetServiceStatus(string service)
{
try
{
var serviceInfo = _cfCli.Run($"service {service}", "getting details for Cloud Foundry service");
var state = new Regex(@"^status:\s+(.*)$", RegexOptions.Multiline).Match(serviceInfo).Groups[1]
.ToString().Trim();
switch (state)
{
case "create in progress":
return Lifecycle.Status.Starting;
case "create succeeded":
return Lifecycle.Status.Online;
case "delete in progress":
return Lifecycle.Status.Stopping;
}
}
catch (CliException e)
{
if (e.Error.Contains($"Service instance {service} not found"))
{
return Lifecycle.Status.Offline;
}
}
return Lifecycle.Status.Unknown;
}
}
}

Просмотреть файл

@ -1,49 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.CloudFoundry
{
internal class CloudFoundryManifest
{
[YamlMember(Alias = "applications")]
public List<Application> Applications { get; set; }= new List<Application>();
public class Application
{
[YamlMember(Alias = "name")]
public string Name { get; set; }
[YamlMember(Alias = "command")]
public string Command { get; set; }
[YamlMember(Alias = "buildpacks")]
public List<string> BuildPacks { get; set; }
[YamlMember(Alias = "stack")]
public string Stack { get; set; }
[YamlMember(Alias = "memory")]
public string Memory { get; set; }
[YamlMember(Alias = "env")]
public Dictionary<string, string> Environment { get; set; }
[YamlMember(Alias = "services")]
public List<string> ServiceNames { get; set; }
}
}
}

Просмотреть файл

@ -1,56 +0,0 @@
using System.IO;
using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.CloudFoundry
{
internal class CloudFoundryManifestFile
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<CloudFoundryManifestFile>();
internal const string DefaultFileName = "manifest-steeltoe.yaml";
internal CloudFoundryManifest CloudFoundryManifest { get; private set; }
internal string File { get; }
internal CloudFoundryManifestFile(string file)
{
File = file;
if (Exists())
{
Load();
}
else
{
CloudFoundryManifest = new CloudFoundryManifest();
}
}
private void Load()
{
Logger.LogDebug($"loading cloud foundry manifest from {File}");
var deserializer = new DeserializerBuilder().Build();
using (var reader = new StreamReader(File))
{
CloudFoundryManifest = deserializer.Deserialize<CloudFoundryManifest>(reader);
}
}
internal void Store()
{
Logger.LogDebug($"storing cloud foundry manifest to {File}");
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(CloudFoundryManifest);
using (var writer = new StreamWriter(File))
{
writer.Write(yaml);
}
}
internal bool Exists()
{
return System.IO.File.Exists(File);
}
}
}

Просмотреть файл

@ -1,57 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Drivers.CloudFoundry
{
internal class CloudFoundryTarget : Target
{
internal CloudFoundryTarget(TargetConfiguration configuration) : base(configuration)
{
}
public override IDriver GetDriver(Context context)
{
return new CloudFoundryDriver(context);
}
public override bool IsHealthy(Context context)
{
var cli = new CloudFoundryCli(context.Shell);
try
{
context.Console.Write($"Cloud Foundry ... ");
context.Console.WriteLine(cli.Run("--version", "getting Cloud Foundry CLI version").Trim());
}
catch (ShellException)
{
context.Console.WriteLine($"!!! {cli.Command} command not found");
return false;
}
try
{
context.Console.Write("logged into Cloud Foundry ... ");
cli.Run("target", "checking if logged into Cloud Foundry");
context.Console.WriteLine("yes");
}
catch (ToolingException)
{
context.Console.WriteLine("!!! no");
return false;
}
return true;
}
}
}

Просмотреть файл

@ -1,23 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Drivers.Docker
{
internal class DockerCli : Cli
{
internal DockerCli(Shell shell) : base("docker", shell)
{
}
}
}

Просмотреть файл

@ -1,172 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text.RegularExpressions;
namespace Steeltoe.Tooling.Drivers.Docker
{
internal class DockerDriver : IDriver
{
private const string Localhost = "127.0.0.1";
private const string HardCodedFramework = "netcoreapp2.1";
private const int HardCodedLocalPort = 8080;
private const int HardCodedRemotePort = 80;
private readonly Context _context;
private readonly DockerCli _dockerCli;
private readonly Cli _dotnetCli;
internal DockerDriver(Context context)
{
_context = context;
_dockerCli = new DockerCli(_context.Shell);
_dotnetCli = new Cli("dotnet", _context.Shell);
}
public void DeploySetup()
{
_dockerCli.Run(
$"network create {GetNetworkName()}",
"creating network");
}
public void DeployTeardown()
{
_dockerCli.Run(
$"network rm {GetNetworkName()}",
"destroying network");
}
private string GetNetworkName()
{
if (_context.Configuration.Apps.Count > 0)
{
return $"{_context.Configuration.Apps.First().Key}-network";
}
return $"{_context.Configuration.Services.First().Key}-network";
}
public void DeployApp(string app)
{
_dotnetCli.Run($"publish -f {HardCodedFramework}", "publishing dotnet app");
var dotnetImage = _context.Target.GetProperty("dotnetRuntimeImage");
var projectDll =
$"bin/Debug/{HardCodedFramework}/publish/{Path.GetFileName(_context.ProjectDirectory)}.dll";
const string appDir = "/app";
var mount = $"{Path.GetFullPath(_context.ProjectDirectory)}:{appDir}";
var portMap = $"{HardCodedLocalPort}:{HardCodedRemotePort}";
_dockerCli.Run(
$"run --name {app} --volume {mount} --workdir {appDir} --env ASPNETCORE_ENVIRONMENT=Docker --publish {portMap} --rm --detach {dotnetImage} dotnet {projectDll}",
"running app in Docker container");
_dockerCli.Run(
$"network connect {GetNetworkName()} {app}",
$"attaching {app} to network");
}
public void UndeployApp(string app)
{
_dockerCli.Run(
$"network disconnect {GetNetworkName()} {app}",
$"detaching {app} from network");
_dockerCli.Run($"stop {app}", "stopping Docker container for app");
}
public Lifecycle.Status GetAppStatus(string app)
{
return GetContainerStatus(app, HardCodedLocalPort);
}
public void DeployService(string service)
{
var dockerInfo = new DockerCli(_context.Shell).Run("info", "getting Docker container OS");
var dockerOs = new Regex(@"OSType:\s*(\S+)", RegexOptions.Multiline).Match(dockerInfo).Groups[1].ToString();
DeployService(service, dockerOs);
_dockerCli.Run(
$"network connect {GetNetworkName()} {service}",
$"attaching {service} to network");
}
public void DeployService(string service, string os)
{
var svcInfo = _context.Configuration.GetServiceInfo(service);
var port = Registry.GetServiceTypeInfo(svcInfo.ServiceType).Port;
var image = LookupImage(svcInfo.ServiceType, os);
var dockerCmd = $"run --name {service} --publish {port}:{port} --detach --rm";
var svcArgs = _context.Configuration.GetServiceArgs(service, "docker") ?? "";
if (svcArgs.Length > 0)
{
svcArgs = svcArgs.Replace("\"", "\"\"\"");
dockerCmd += $" {svcArgs}";
}
dockerCmd += $" {image}";
_dockerCli.Run(dockerCmd, "running Docker container for service");
}
public void UndeployService(string service)
{
_dockerCli.Run(
$"network disconnect {GetNetworkName()} {service}",
$"detaching {service} from network");
_dockerCli.Run($"stop {service}", "stopping Docker container for service");
}
public Lifecycle.Status GetServiceStatus(string service)
{
var svcInfo = _context.Configuration.GetServiceInfo(service);
var port = Registry.GetServiceTypeInfo(svcInfo.ServiceType).Port;
return GetContainerStatus(service, port);
}
private Lifecycle.Status GetContainerStatus(string name, int port)
{
var containerInfo = _dockerCli.Run($"ps --no-trunc --filter name=^/{name}$", "getting Docker container status").Split('\n');
if (containerInfo.Length <= 2)
{
return Lifecycle.Status.Offline;
}
var statusStart = containerInfo[0].IndexOf("STATUS", StringComparison.Ordinal);
if (!containerInfo[1].Substring(statusStart).StartsWith("Up "))
{
return Lifecycle.Status.Unknown;
}
try
{
new TcpClient(Localhost, port).Dispose();
return Lifecycle.Status.Online;
}
catch (SocketException)
{
return Lifecycle.Status.Starting;
}
}
private string LookupImage(string type, string os)
{
var images = _context.Target.Configuration.ServiceTypeProperties[type];
return images.TryGetValue($"image-{os}", out var image) ? image : images["image"];
}
}
}

Просмотреть файл

@ -1,64 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Text.RegularExpressions;
namespace Steeltoe.Tooling.Drivers.Docker
{
internal class DockerTarget : Target
{
internal DockerTarget(TargetConfiguration configuration) : base(configuration)
{
}
public override IDriver GetDriver(Context context)
{
return new DockerDriver(context);
}
public override bool IsHealthy(Context context)
{
var console = context.Console;
console.Write("Docker ... ");
var cli = new DockerCli(context.Shell);
try
{
var dockerVersion = cli.Run("--version", "getting Docker CLI version").Trim();
console.WriteLine(dockerVersion);
var dockerInfo = cli.Run("info", "getting Docker info");
console.Write("Docker host OS ... ");
context.Console.WriteLine(new Regex(@"Operating System:\s*(.+)", RegexOptions.Multiline)
.Match(dockerInfo).Groups[1].ToString());
console.Write("Docker container OS ... ");
context.Console.WriteLine(new Regex(@"OSType:\s*(.+)", RegexOptions.Multiline)
.Match(dockerInfo).Groups[1].ToString());
return true;
}
catch (CliException e)
{
context.Console.WriteLine($"!!! {e.Message}");
return false;
}
catch (ShellException)
{
context.Console.WriteLine($"!!! {cli.Command} command not found");
return false;
}
}
}
}

Просмотреть файл

@ -1,94 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Drivers.Dummy
{
internal class DummyDriver : IDriver
{
private readonly string _path;
private DummyServiceDatabase _database;
internal DummyDriver(string path)
{
_path = path;
_database = DummyServiceDatabase.Load(_path);
}
public void DeploySetup()
{
}
public void DeployTeardown()
{
}
public void DeployApp(string app)
{
_database.Apps.Add(app);
Store();
}
public void UndeployApp(string app)
{
_database.Apps.Remove(app);
Store();
}
public Lifecycle.Status GetAppStatus(string app)
{
return _database.Apps.Contains(app) ? Lifecycle.Status.Online : Lifecycle.Status.Offline;
}
public void DeployService(string service)
{
_database.Services[service] = Lifecycle.Status.Starting;
Store();
}
public void UndeployService(string service)
{
_database.Services[service] = Lifecycle.Status.Stopping;
Store();
}
public Lifecycle.Status GetServiceStatus(string service)
{
if (!_database.Services.ContainsKey(service))
{
return Lifecycle.Status.Offline;
}
var state = _database.Services[service];
switch (state)
{
case Lifecycle.Status.Starting:
_database.Services[service] = Lifecycle.Status.Online;
Store();
break;
case Lifecycle.Status.Stopping:
_database.Services.Remove(service);
Store();
break;
}
return state;
}
private void Store()
{
DummyServiceDatabase.Store(_path, _database);
}
}
}

Просмотреть файл

@ -1,70 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using System.IO;
using System.Threading;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.Dummy
{
internal class DummyServiceDatabase
{
public List<string> Apps { get; set; } = new List<string>();
public SortedDictionary<string, Lifecycle.Status> Services { get; set; } =
new SortedDictionary<string, Lifecycle.Status>();
internal static void Store(string path, DummyServiceDatabase database)
{
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(database);
using (var fOut = GetFileStream(path, FileMode.Create, FileAccess.Write))
{
using (var writer = new StreamWriter(fOut))
{
writer.Write(yaml);
}
}
}
internal static DummyServiceDatabase Load(string path)
{
var deserializer = new DeserializerBuilder().Build();
using (var fIn = GetFileStream(path, FileMode.OpenOrCreate, FileAccess.Read))
{
using (var reader = new StreamReader(fIn))
{
return deserializer.Deserialize<DummyServiceDatabase>(reader) ??
new DummyServiceDatabase();
}
}
}
private static FileStream GetFileStream(string path, FileMode mode, FileAccess access)
{
while (true)
{
try
{
return new FileStream(path, mode, access, FileShare.None);
}
catch (IOException)
{
Thread.Sleep(100);
}
}
}
}
}

Просмотреть файл

@ -1,36 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
namespace Steeltoe.Tooling.Drivers.Dummy
{
internal class DummyTarget : Target
{
internal DummyTarget(TargetConfiguration configuration) : base(configuration)
{
}
public override IDriver GetDriver(Context context)
{
return new DummyDriver(Path.Combine(context.ProjectDirectory, "dummy-service-driver.db"));
}
public override bool IsHealthy(Context context)
{
context.Console.WriteLine("dummy tool version ... 0.0.0");
return true;
}
}
}

Просмотреть файл

@ -1,67 +0,0 @@
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
/// <summary>
/// Represents a Kubernetes resource configuration.
/// </summary>
public class KubernetesConfig
{
/// <summary>
/// API version.
/// </summary>
[YamlMember(Alias = "apiVersion", Order = -2)]
public string ApiVersion { get; set; }
/// <summary>
/// Resource kind, e.g. Service or Deployment.
/// </summary>
[YamlMember(Alias = "kind", Order = -2)]
public string Kind { get; set; }
/// <summary>
/// Resource metadata.
/// </summary>
[YamlMember(Alias = "metadata", Order = -2)]
public ConfigMetaData MetaData { get; set; }
/// <summary>
/// Resource metadata structure.
/// </summary>
public class ConfigMetaData
{
/// <summary>
/// Resource name.
/// </summary>
[YamlMember(Alias = "name")] public string Name { get; set; }
/// <summary>
/// Resource labels, e.g. "tier" -> "frontend".
/// </summary>
[YamlMember(Alias = "labels")]
public Dictionary<string, string> Labels { get; set; } = new Dictionary<string, string>();
}
/// <summary>
/// Resource service ports structure.
/// </summary>
public class ServicePorts
{
/// <summary>
/// Service port.
/// </summary>
[YamlMember(Alias = "port")] public int Port { get; set; }
/// <summary>
/// Service target port.
/// </summary>
[YamlMember(Alias = "targetPort")] public int TargetPort { get; set; }
/// <summary>
/// Service container port.
/// </summary>
[YamlMember(Alias = "containerPort")] public int ContainerPort { get; set; }
}
}
}

Просмотреть файл

@ -1,82 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesDeploymentConfig : KubernetesConfig
{
[YamlMember(Alias = "spec")] public DeploymentSpec Spec { get; set; }
public class DeploymentSpec
{
[YamlMember(Alias = "replicas")] public int Replicas { get; set; }
[YamlMember(Alias = "selector")] public ServiceSelector Selector { get; set; }
[YamlMember(Alias = "template")] public ServiceTemplate Template { get; set; }
public class ServiceSelector
{
[YamlMember(Alias = "matchLabels")]
public Dictionary<string, string> MatchLabels { get; set; } = new Dictionary<string, string>();
}
public class ServiceTemplate
{
[YamlMember(Alias = "metadata")] public ServiceMetaData Metadata { get; set; }
[YamlMember(Alias = "spec")] public TemplateSpec Spec { get; set; }
public class ServiceMetaData
{
[YamlMember(Alias = "labels")]
public Dictionary<string, string> Labels { get; set; } = new Dictionary<string, string>();
}
public class TemplateSpec
{
[YamlMember(Alias = "containers")]
public List<Container> Containers { get; set; } = new List<Container>();
public class Container
{
[YamlMember(Alias = "name")] public string Name { get; set; }
[YamlMember(Alias = "image")] public string Image { get; set; }
[YamlMember(Alias = "imagePullPolicy")]
public string ImagePullPolicy { get; set; }
[YamlMember(Alias = "ports")]
public List<ServicePorts> Ports { get; set; }
[YamlMember(Alias = "env")]
public List<NameValuePair> Env { get; set; }
public class NameValuePair
{
[YamlMember(Alias = "name")] public string Name { get; set; }
[YamlMember(Alias = "value")] public string Value { get; set; }
}
}
}
}
}
}
}

Просмотреть файл

@ -1,55 +0,0 @@
using System.IO;
using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesDeploymentConfigFile
{
private static readonly ILogger Logger =
Logging.LoggerFactory.CreateLogger<KubernetesDeploymentConfigFile>();
internal KubernetesDeploymentConfig KubernetesDeploymentConfig { get; private set; }
internal string File { get; }
internal KubernetesDeploymentConfigFile(string file)
{
File = file;
if (Exists())
{
Load();
}
else
{
KubernetesDeploymentConfig = new KubernetesDeploymentConfig();
}
}
private void Load()
{
Logger.LogDebug($"loading kubernetes deployment config from {File}");
var deserializer = new DeserializerBuilder().Build();
using (var reader = new StreamReader(File))
{
KubernetesDeploymentConfig = deserializer.Deserialize<KubernetesDeploymentConfig>(reader);
}
}
internal void Store()
{
Logger.LogDebug($"storing kubernetes deployment config to {File}");
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(KubernetesDeploymentConfig);
using (var writer = new StreamWriter(File))
{
writer.Write(yaml);
}
}
internal bool Exists()
{
return System.IO.File.Exists(File);
}
}
}

Просмотреть файл

@ -1,35 +0,0 @@
using System.Collections.Generic;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
/// <summary>
/// Represents a Dockerfile for a Dotnet application.
/// </summary>
public class KubernetesDotnetAppDockerfile
{
/// <summary>
/// Base Docker image form which to build Dotnet application image.
/// </summary>
public string BaseImage { get; set; }
/// <summary>
/// Dotnet application name.
/// </summary>
public string App { get; set; }
/// <summary>
/// Path containing Dotnet application.
/// </summary>
public string AppPath { get; set; }
/// <summary>
/// Path to Dotnet application build.
/// </summary>
public string BuildPath { get; set; }
/// <summary>
/// Docker container environment.
/// </summary>
public string Environment { get; set; }
}
}

Просмотреть файл

@ -1,65 +0,0 @@
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesDotnetAppDockerfileFile
{
private static readonly ILogger Logger =
Logging.LoggerFactory.CreateLogger<KubernetesDotnetAppDockerfileFile>();
internal string File { get; }
internal KubernetesDotnetAppDockerfile KubernetesDotnetAppDockerfile { get; private set; }
internal KubernetesDotnetAppDockerfileFile(string file)
{
File = file;
if (Exists())
{
Load();
}
else
{
KubernetesDotnetAppDockerfile = new KubernetesDotnetAppDockerfile();
}
}
private void Load()
{
Logger.LogDebug($"loading kubernetes dotnet app dockerfile from {File}");
string text = System.IO.File.ReadAllText(File);
KubernetesDotnetAppDockerfile = new KubernetesDotnetAppDockerfile()
{
BaseImage = new Regex(@"^FROM\s+(\S+)", RegexOptions.Multiline)
.Match(text).Groups[1].ToString(),
App = new Regex(@"^CMD dotnet (.+)\.dll\s+", RegexOptions.Multiline)
.Match(text).Groups[1].ToString(),
AppPath = new Regex(@"^WORKDIR\s+(\S+)", RegexOptions.Multiline)
.Match(text).Groups[1].ToString(),
BuildPath = new Regex(@"^COPY\s+(\S+)", RegexOptions.Multiline)
.Match(text).Groups[1].ToString(),
Environment = new Regex(@"^ENV\s+ASPNETCORE_ENVIRONMENT\s+(\S+)", RegexOptions.Multiline)
.Match(text).Groups[1].ToString(),
};
}
internal void Store()
{
Logger.LogDebug($"storing kubernetes dotnet app dockerfile to {File}");
System.IO.File.WriteAllText(File, $@"FROM {KubernetesDotnetAppDockerfile.BaseImage}
COPY {KubernetesDotnetAppDockerfile.BuildPath} {KubernetesDotnetAppDockerfile.AppPath}
ENV ASPNETCORE_ENVIRONMENT {KubernetesDotnetAppDockerfile.Environment}
WORKDIR {KubernetesDotnetAppDockerfile.AppPath}
CMD dotnet {KubernetesDotnetAppDockerfile.App}.dll
");
}
internal bool Exists()
{
return System.IO.File.Exists(File);
}
}
}

Просмотреть файл

@ -1,280 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesDriver : IDriver
{
private readonly Context _context;
private readonly Cli _kubectlCli;
private readonly Cli _dockerCli;
private const string ServiceKind = "Service";
private const string HardCodedServiceApiVersion = "v1";
private const string DeploymentKind = "Deployment";
private const string NodePort = "NodePort";
private const string ImagePullNever = "Never";
private const string HardCodedDeploymentApiVersion = "apps/v1";
internal KubernetesDriver(Context context)
{
_context = context;
_kubectlCli = new KubernetesCli(context.Shell);
_dockerCli = new DockerCli(context.Shell);
}
public void DeploySetup()
{
}
public void DeployTeardown()
{
}
public void DeployApp(string app)
{
KubernetesDotnetAppDockerfileFile dockerfileFile = new KubernetesDotnetAppDockerfileFile("Dockerfile");
var dockerfile = dockerfileFile.KubernetesDotnetAppDockerfile;
dockerfile.App = app;
dockerfile.AppPath = "/app";
dockerfile.BaseImage = "steeltoeoss/dotnet-runtime:2.1";
dockerfile.BuildPath = "bin/Debug/netcoreapp2.1/publish";
dockerfile.Environment = "Docker";
dockerfileFile.Store();
_dockerCli.Run($"build --tag {app.ToLower()} .", "building Docker image for app");
void PreSaveAction(KubernetesDeploymentConfig deployCfg, KubernetesServiceConfig svcCfg)
{
deployCfg.Spec.Template.Spec.Containers[0].ImagePullPolicy = ImagePullNever;
deployCfg.Spec.Template.Spec.Containers[0].Env =
new List<KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate.TemplateSpec.Container.
NameValuePair>
{
new KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate.TemplateSpec.Container.
NameValuePair() {Name = "GET_HOSTS_FROM", Value = "dns"}
};
svcCfg.Spec.Type = NodePort;
}
// TODO: get 'port' from somewhere else
// TODO: get 'image' from somewhere else
DeployKubernetesService(app, app.ToLower(), 80, PreSaveAction);
// var appPodInfo = _kubectlCli.Run($"get pods --selector app={app.ToLower()}", "getting app pod");
// var pod = new Regex($"^({app.ToLower()}-\\S+)", RegexOptions.Multiline).Match(appPodInfo).Groups[1].ToString();
// _kubectlCli.Run($"port-forward {pod} 8080:80", "forwarding port 8080->80");
}
public void UndeployApp(string app)
{
UndeployKubernetesService(app);
}
public Lifecycle.Status GetAppStatus(string app)
{
return GetKubernetesServiceStatus(app);
}
public void DeployService(string service)
{
// TODO: get 'os' from from docker command
DeployService(service, "linux");
}
public void UndeployService(string service)
{
UndeployKubernetesService(service);
}
public Lifecycle.Status GetServiceStatus(string service)
{
return GetKubernetesServiceStatus(service);
}
internal void DeployService(string service, string os)
{
var svcInfo = _context.Configuration.GetServiceInfo(service);
var port = Registry.GetServiceTypeInfo(svcInfo.ServiceType).Port;
var image = LookupImage(svcInfo.ServiceType, os);
DeployKubernetesService(service, image, port);
}
private void DeployKubernetesService(String name, String image, int port,
Action<KubernetesDeploymentConfig, KubernetesServiceConfig> preSaveAction = null)
{
var deployCfgFile = new KubernetesDeploymentConfigFile($"{name}-deployment.yaml");
var deployCfg = deployCfgFile.KubernetesDeploymentConfig;
deployCfg.ApiVersion = HardCodedDeploymentApiVersion;
deployCfg.Kind = DeploymentKind;
deployCfg.MetaData = new KubernetesConfig.ConfigMetaData()
{
Name = name.ToLower(),
Labels = new Dictionary<string, string>()
{
{"app", name.ToLower()}
}
};
deployCfg.Spec = new KubernetesDeploymentConfig.DeploymentSpec()
{
Selector = new KubernetesDeploymentConfig.DeploymentSpec.ServiceSelector()
{
MatchLabels = new Dictionary<string, string>()
{
{"app", name.ToLower()}
}
},
Template = new KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate()
{
Metadata = new KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate.ServiceMetaData()
{
Labels = new Dictionary<string, string>()
{
{"app", name.ToLower()}
}
},
Spec = new KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate.TemplateSpec()
{
Containers =
new List<KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate.TemplateSpec.Container>()
{
new KubernetesDeploymentConfig.DeploymentSpec.ServiceTemplate.TemplateSpec.Container()
{
Name = name.ToLower(),
Image = image,
Ports = new List<KubernetesConfig.ServicePorts>()
{
new KubernetesConfig.ServicePorts()
{
ContainerPort = port
}
}
}
}
}
}
};
var svcCfgFile = new KubernetesServiceConfigFile($"{name}-service.yaml");
var svcCfg = svcCfgFile.KubernetesServiceConfig;
svcCfg.ApiVersion = HardCodedServiceApiVersion;
svcCfg.Kind = ServiceKind;
svcCfg.MetaData = new KubernetesConfig.ConfigMetaData()
{
Name = name.ToLower()
};
svcCfg.Spec = new KubernetesServiceConfig.ServiceSpec()
{
Ports = new List<KubernetesConfig.ServicePorts>()
{
new KubernetesConfig.ServicePorts()
{
Port = port
}
},
Selector = new Dictionary<string, string>()
{
{"app", name.ToLower()}
}
};
preSaveAction?.Invoke(deployCfg, svcCfg);
deployCfgFile.Store();
svcCfgFile.Store();
_kubectlCli.Run($"apply --filename {deployCfgFile.File}", "applying Kubernetes deployment configuration");
_kubectlCli.Run($"apply --filename {svcCfgFile.File}", "applying Kubernetes service configuration");
}
private void UndeployKubernetesService(string name)
{
try
{
_kubectlCli.Run($"delete --filename {name}-service.yaml", "deleting Kubernetes service");
}
catch (CliException)
{
_context.Console.WriteLine($"hmm, Kubernetes service doesn't seem to exist: {name}");
}
_kubectlCli.Run($"delete --filename {name}-deployment.yaml", "deleting Kubernetes deployment");
}
private Lifecycle.Status GetKubernetesServiceStatus(String name)
{
var podInfo = _kubectlCli.Run($"get pods --selector app={name.ToLower()}",
"getting Kubernetes deployment status");
if (podInfo.Contains("Running"))
{
return Lifecycle.Status.Online;
}
else if (podInfo.Contains("Pending") || podInfo.Contains("ContainerCreating"))
{
return Lifecycle.Status.Starting;
}
else if (podInfo.Contains("Terminating"))
{
return Lifecycle.Status.Stopping;
}
else if (podInfo.Contains("CrashLoopBackOff")) // TODO: is this the correct assumption? need a new state?
{
return Lifecycle.Status.Online;
}
else if (string.IsNullOrEmpty(podInfo))
{
try
{
_kubectlCli.Run($"get services {name.ToLower()}", "getting Kubernetes service status");
return Lifecycle.Status.Stopping;
}
catch (CliException)
{
return Lifecycle.Status.Offline;
}
}
return Lifecycle.Status.Unknown;
}
private string LookupImage(string type, string os)
{
var images = _context.Target.Configuration.ServiceTypeProperties[type];
return images.TryGetValue($"image-{os}", out var image) ? image : images["image"];
}
}
internal class KubernetesCli : Cli
{
internal KubernetesCli(Shell shell) : base("kubectl", shell)
{
}
}
internal class DockerCli : Cli
{
public DockerCli(Shell shell) : base("docker", shell)
{
}
}
}

Просмотреть файл

@ -1,34 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesServiceConfig : KubernetesConfig
{
[YamlMember(Alias = "spec")] public ServiceSpec Spec { get; set; }
public class ServiceSpec
{
[YamlMember(Alias = "type")] public string Type { get; set; }
[YamlMember(Alias = "selector")]
public Dictionary<string, string> Selector { get; set; } = new Dictionary<string, string>();
[YamlMember(Alias = "ports")] public List<ServicePorts> Ports { get; set; } = new List<ServicePorts>();
}
}
}

Просмотреть файл

@ -1,54 +0,0 @@
using System.IO;
using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesServiceConfigFile
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<KubernetesServiceConfigFile>();
internal KubernetesServiceConfig KubernetesServiceConfig { get; private set; }
internal string File { get; }
internal KubernetesServiceConfigFile(string file)
{
File = file;
if (Exists())
{
Load();
}
else
{
KubernetesServiceConfig = new KubernetesServiceConfig();
}
}
private void Load()
{
Logger.LogDebug($"loading kubernetes service config from {File}");
var deserializer = new DeserializerBuilder().Build();
using (var reader = new StreamReader(File))
{
KubernetesServiceConfig = deserializer.Deserialize<KubernetesServiceConfig>(reader);
}
}
internal void Store()
{
Logger.LogDebug($"storing kubernetes service config to {File}");
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(KubernetesServiceConfig);
using (var writer = new StreamWriter(File))
{
writer.Write(yaml);
}
}
internal bool Exists()
{
return System.IO.File.Exists(File);
}
}
}

Просмотреть файл

@ -1,69 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Text.RegularExpressions;
namespace Steeltoe.Tooling.Drivers.Kubernetes
{
internal class KubernetesTarget : Target
{
internal KubernetesTarget(TargetConfiguration configuration) : base(configuration)
{
}
public override IDriver GetDriver(Context context)
{
return new KubernetesDriver(context);
}
public override bool IsHealthy(Context context)
{
var cli = new KubernetesCli(context.Shell);
try
{
context.Console.Write($"Kubernetes ... ");
var versionInfo = cli.Run("version", "getting Kubernetes CLI version");
var matcher =
new Regex(@"Client Version:.*Major:""(\d+).*Minor:""(\d+)", RegexOptions.Multiline).Match(
versionInfo);
var clientVersion = $"{matcher.Groups[1]}.{matcher.Groups[2]}";
matcher =
new Regex(@"Server Version:.*Major:""(\d+).*Minor:""(\d+)", RegexOptions.Multiline).Match(
versionInfo);
var serverVersion = $"{matcher.Groups[1]}.{matcher.Groups[2]}";
context.Console.WriteLine($"kubectl client version {clientVersion}, server version {serverVersion}");
}
catch (ShellException)
{
context.Console.WriteLine($"!!! {cli.Command} command not found");
return false;
}
try
{
context.Console.Write("current context ... ");
var contextInfo = cli.Run("config get-contexts", "getting Kubernetes context");
var matcher = new Regex(@"\*\s+(\S+)", RegexOptions.Multiline).Match(contextInfo);
context.Console.WriteLine(matcher.Groups[1]);
}
catch (ToolingException)
{
context.Console.WriteLine("!!!");
return false;
}
return true;
}
}
}

Просмотреть файл

@ -1,51 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to add an application or service to the Steeltoe Tooling configuration.
/// </summary>
[RequiresInitialization]
public class AddAppExecutor : Executor
{
private readonly string _name;
private readonly string _framework;
private readonly string _runtime;
/// <summary>
/// Create a new workflow to add an application to the Steeltoe Tooling configuration.
/// </summary>
/// <param name="appName">Application name.</param>
/// <param name="framework">Target framework.</param>
/// <param name="runtime">Target runtime.</param>
public AddAppExecutor(string appName, string framework, string runtime)
{
_name = appName;
_framework = framework;
_runtime = runtime;
}
/// <summary>
/// Add the application or service to the Steeltoe Tooling configuration.
/// </summary>
protected override void Execute()
{
Context.Configuration.AddApp(_name, _framework, _runtime);
Context.Console.WriteLine($"Added app '{_name}' ({_framework}/{_runtime})");
}
}
}

Просмотреть файл

@ -1,47 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to add a service to the Steeltoe Tooling configuration.
/// </summary>
[RequiresInitialization]
public class AddServiceExecutor : Executor
{
private readonly string _name;
private readonly string _serviceType;
/// <summary>
/// Create a new workflow to add a service to the Steeltoe Tooling configuration.
/// </summary>
/// <param name="serviceName">Service name.</param>
/// <param name="serviceType">Service type.</param>
public AddServiceExecutor(string serviceName, string serviceType)
{
_name = serviceName;
_serviceType = serviceType;
}
/// <summary>
/// Add the application or service to the Steeltoe Tooling configuration.
/// </summary>
protected override void Execute()
{
Context.Configuration.AddService(_name, _serviceType);
Context.Console.WriteLine($"Added {_serviceType} service '{_name}'");
}
}
}

Просмотреть файл

@ -1,60 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// An abstract class representing a workflow relating to an application or service.
/// </summary>
public abstract class AppOrServiceExecutor : Executor
{
/// <summary>
/// The name of the related application or service.
/// </summary>
protected string AppOrServiceName { get; private set; }
/// <summary>
/// Create a workflow relating to an application or service.
/// </summary>
/// <param name="appOrServiceName"></param>
protected AppOrServiceExecutor(string appOrServiceName)
{
AppOrServiceName = appOrServiceName;
}
/// <summary>
/// Execute this workflow.
/// </summary>
/// <exception cref="ItemDoesNotExistException">If the application or service relating to this workflow does not exist.</exception>
protected override void Execute()
{
if (Context.Configuration.GetApps().Contains(AppOrServiceName))
{
ExecuteForApp();
}
else if (Context.Configuration.GetServices().Contains(AppOrServiceName))
{
ExecuteForService();
}
else
{
throw new ItemDoesNotExistException(AppOrServiceName, "app or service");
}
}
internal abstract void ExecuteForApp();
internal abstract void ExecuteForService();
}
}

Просмотреть файл

@ -1,84 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Threading;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to deploy applications and dependent services to the current target.
/// </summary>
[RequiresTarget]
public class DeployExecutor : GroupExecutor
{
/// <summary>
/// Create a new workflow to deploy applications and dependent services to the current target.
/// </summary>
public DeployExecutor() : base(false)
{
}
/// <summary>
/// Calls Driver.DeploySetup then defers to base class.
/// </summary>
protected override void Execute()
{
Context.Driver.DeploySetup();
base.Execute();
}
/// <summary>
/// Deploys apps then blocks until all apps online.
/// </summary>
/// <param name="apps">Apps to deploy.</param>
protected override void ExecuteForApps(List<string> apps)
{
base.ExecuteForApps(apps);
WaitUntilAllTransitioned(apps, Context.Driver.GetAppStatus, Lifecycle.Status.Online);
}
/// <summary>
/// Deploys services then blocks until all services online.
/// </summary>
/// <param name="services">Services to deploy.</param>
protected override void ExecuteForServices(List<string> services)
{
base.ExecuteForServices(services);
WaitUntilAllTransitioned(services, Context.Driver.GetServiceStatus, Lifecycle.Status.Online);
}
/// <summary>
/// Deploy the app.
/// </summary>
/// <param name="app">App name.</param>
protected override void ExecuteForApp(string app)
{
Context.Console.WriteLine($"Deploying app '{app}'");
new Lifecycle(Context, app).Deploy();
}
/// <summary>
/// Deploy the service.
/// </summary>
/// <param name="service">Service name.</param>
protected override void ExecuteForService(string service)
{
Context.Console.WriteLine($"Deploying service '{service}'");
new Lifecycle(Context, service).Deploy();
}
}
}

Просмотреть файл

@ -1,59 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to get the arguments of an application or service.
/// </summary>
[RequiresInitialization]
public class GetArgsExecutor : AppOrServiceExecutor
{
private readonly string _target;
/// <summary>
/// A workflow to display the arguments for an application or service.
/// If <code>target</code> is null, display the application or service arguments.
/// If <code>target</code> is not null, display the arguments for deploying the application or service.
/// </summary>
/// <param name="appOrServiceName">Application or service name.</param>
/// <param name="target">Deployment target name (can be null).</param>
public GetArgsExecutor(string appOrServiceName, string target = null) : base(appOrServiceName)
{
_target = target;
}
internal override void ExecuteForApp()
{
ShowArgs(_target == null
? Context.Configuration.GetAppArgs(AppOrServiceName)
: Context.Configuration.GetAppArgs(AppOrServiceName, _target));
}
internal override void ExecuteForService()
{
ShowArgs(_target == null
? Context.Configuration.GetServiceArgs(AppOrServiceName)
: Context.Configuration.GetServiceArgs(AppOrServiceName, _target));
}
private void ShowArgs(string args)
{
if (args != null)
{
Context.Console.WriteLine(args);
}
}
}
}

Просмотреть файл

@ -1,138 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Threading;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// An abstract workflow operating on a group of applications and dependent services.
/// </summary>
public abstract class GroupExecutor : Executor
{
private readonly bool _appsFirst;
/// <summary>
/// Create a workflow to operate on a group of applications and dependent services.
/// </summary>
/// <param name="appsFirst">Whether applications or services are operated on first.</param>
protected GroupExecutor(Boolean appsFirst)
{
_appsFirst = appsFirst;
}
/// <summary>
/// Execute this workflow on the applications and dependent services.
/// </summary>
protected override void Execute()
{
var services = Context.Configuration.GetServices();
var apps = Context.Configuration.GetApps();
if (_appsFirst)
{
ExecuteForApps(apps);
ExecuteForServices(services);
}
else
{
ExecuteForServices(services);
ExecuteForApps(apps);
}
}
/// <summary>
/// Calls <see cref="ExecuteForApp"/> for each app.
/// </summary>
/// <param name="apps">Apps on which to be executed</param>
protected virtual void ExecuteForApps(List<string> apps)
{
foreach (var app in apps)
{
ExecuteForApp(app);
}
}
/// <summary>
/// Calls <see cref="ExecuteForService"/> for each service.
/// </summary>
/// <param name="services">Services on which to be executed</param>
protected virtual void ExecuteForServices(List<string> services)
{
foreach (var service in services)
{
ExecuteForService(service);
}
}
/// <summary>
/// Subclasses implement their business logic for executing on an app.
/// </summary>
/// <param name="app">App on which to be executed.</param>
protected abstract void ExecuteForApp(string app);
/// <summary>
/// Subclasses implement their business logic for executing on a service.
/// </summary>
/// <param name="service">Service on which to be executed.</param>
protected abstract void ExecuteForService(string service);
/// <summary>
/// A convenience for subclasses to wait until all apps (or services) have transitioned to a desired state.
/// </summary>
/// <param name="appsOrServices">A list of either app or service names.</param>
/// <param name="statusCheck">A function that returns the status of an app or service.</param>
/// <param name="status">The desired state.</param>
/// <exception cref="ToolingException">If <see cref="Settings.MaxChecks"/> exceeded.</exception>
protected void WaitUntilAllTransitioned(List<string> appsOrServices, Func<string, Lifecycle.Status> statusCheck,
Lifecycle.Status status)
{
foreach (var appOrService in appsOrServices)
{
var count = 0;
while (true)
{
++count;
if (Settings.MaxChecks > 0)
{
if (count > Settings.MaxChecks)
{
throw new ToolingException($"max checks exceeded ({Settings.MaxChecks})");
}
}
if (statusCheck(appOrService) == status)
{
break;
}
const int ticksPerMillis = 10000;
const int oneSecondMillis = 1000;
var startTicks = DateTime.Now.Ticks;
var elapsedMillis = (DateTime.Now.Ticks - startTicks) / ticksPerMillis;
var waitMillis = oneSecondMillis - elapsedMillis;
if (waitMillis > 0L)
{
Thread.Sleep((int) waitMillis);
}
Context.Console.WriteLine(
$"Waiting for '{appOrService}' to transition to {status.ToString().ToLower()} ({count})");
}
}
}
}
}

Просмотреть файл

@ -1,84 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
using Steeltoe.Tooling.Scanners;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to initialize the Steeltoe Tooling configuration.
/// </summary>
public class InitializationExecutor : Executor
{
private readonly string _path;
private readonly bool _autodetect;
private readonly bool _force;
/// <summary>
/// Create a workflow to initialize the Steeltoe Tooling configuration file.
/// If the <paramref name="path"/> is null, the default path is used.
/// If the <paramref name="path"/> is a directory, the path is the directory joined with the default file name.
/// </summary>
/// <param name="path">Path to the Steeltoe Configuration file.</param>
/// <param name="autodetect">Detect apps when initializing.</param>
/// <param name="force">Forces the overwriting of an existing configuration file.</param>
/// <seealso cref="ConfigurationFile"/>.
public InitializationExecutor(string path = null, bool autodetect = false, bool force = false)
{
_path = path;
_autodetect = autodetect;
_force = force;
}
/// <summary>
/// Initialize the Steeltoe Configuration file.
/// </summary>
/// <exception cref="ToolingException">If an error occurs when initialization the Steeltoe Configuration file.</exception>
protected override void Execute()
{
var path = _path == null
? Context.ProjectDirectory
: Path.Combine(Context.ProjectDirectory, _path);
var cfgFile = new ConfigurationFile(path);
if (cfgFile.Exists())
{
if (!_force)
{
throw new ToolingException("Steeltoe Developer Tools already initialized");
}
File.Delete(cfgFile.File);
cfgFile = new ConfigurationFile(path);
}
Context.Configuration = cfgFile.Configuration;
if (_autodetect)
{
foreach (var appInfo in new AppScanner().Scan(Context.ProjectDirectory))
{
// TODO: guess framework/runtime rather than hardcode
new AddAppExecutor(appInfo.App, "netcoreapp2.1", "win10-x64").Execute(Context);
}
}
cfgFile.Store();
Context.Console.WriteLine("Initialized Steeltoe Developer Tools");
}
}
}

Просмотреть файл

@ -1,76 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Linq;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to display the applications and dependent services of the Steeltoe Tooling configuration.
/// </summary>
[RequiresInitialization]
public class ListExecutor : GroupExecutor
{
private readonly bool _verbose;
private string _format;
/// <summary>
/// Create a workflow to display the applications and dependent services of the Steeltoe Tooling configuration.
/// </summary>
/// <param name="verbose"></param>
public ListExecutor(bool verbose = false) : base(false)
{
_verbose = verbose;
}
/// <summary>
/// Display the applications and dependent services of the Steeltoe Tooling configuration.
/// </summary>
protected override void Execute()
{
var services = Context.Configuration.GetServices();
if (_verbose)
{
var max = services.Max(n => n.Length);
_format = "{0,-" + max + "} {1,5} {2}";
}
else
{
_format = "{0}";
}
base.Execute();
}
/// <summary>
/// Print app information.
/// </summary>
/// <param name="app">App name.</param>
protected override void ExecuteForApp(string app)
{
Context.Console.WriteLine(_format, app, "", "app");
}
/// <summary>
/// Print service information.
/// </summary>
/// <param name="service">Service name.</param>
protected override void ExecuteForService(string service)
{
var svcInfo = Context.Configuration.GetServiceInfo(service);
var svcTypeInfo = Registry.GetServiceTypeInfo(svcInfo.ServiceType);
Context.Console.WriteLine(_format, service, svcTypeInfo.Port, svcTypeInfo.Name);
}
}
}

Просмотреть файл

@ -1,52 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Linq;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to list available service types.
/// </summary>
public class ListServiceTypesExecutor : ListExecutor
{
/// <summary>
/// Creates a workflow to list available service types.
/// </summary>
/// <param name="verbose">if true, be verbose</param>
public ListServiceTypesExecutor(bool verbose = false) : base(verbose)
{
}
internal void ExecuteList(Context context)
{
foreach (var svcType in Registry.GetServiceTypes())
{
context.Console.WriteLine(svcType);
}
}
internal void ExecuteListVerbose(Context context)
{
var svcTypeNames = Registry.GetServiceTypes();
var max = svcTypeNames.Max(n => n.Length);
var format = "{0,-" + max + "} {1,5} {2}";
foreach (var svcTypeName in svcTypeNames)
{
var svcTypeInfo = Registry.GetServiceTypeInfo(svcTypeName);
context.Console.WriteLine(format, svcTypeInfo.Name, svcTypeInfo.Port, svcTypeInfo.Description);
}
}
}
}

Просмотреть файл

@ -1,52 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Linq;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to list available deployment targets.
/// </summary>
public class ListTargetsExecutor : ListExecutor
{
/// <summary>
/// Creates a workflow to list available deployment targets.
/// </summary>
/// <param name="verbose">if true, be verbose</param>
public ListTargetsExecutor(bool verbose = false) : base(verbose)
{
}
internal void ExecuteList(Context context)
{
foreach (var envName in Registry.Targets)
{
context.Console.WriteLine(envName);
}
}
internal void ExecuteListVerbose(Context context)
{
var targets = Registry.Targets;
var max = targets.Max(n => n.Length);
var format = "{0,-" + max + "} {1}";
foreach (var target in targets)
{
var tgtInfo = Registry.GetTarget(target);
context.Console.WriteLine(format, tgtInfo.Name, tgtInfo.Description);
}
}
}
}

Просмотреть файл

@ -1,44 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to remove an application or service from the Steeltoe Tooling configuration.
/// </summary>
[RequiresInitialization]
public class RemoveExecutor : AppOrServiceExecutor
{
/// <summary>
/// Create a new workflow to remove an application or service from the Steeltoe Tooling configuration.
/// </summary>
/// <param name="appOrServiceName">Application or service name.</param>
public RemoveExecutor(string appOrServiceName) : base(appOrServiceName)
{
}
internal override void ExecuteForApp()
{
Context.Configuration.RemoveApp(AppOrServiceName);
Context.Console.WriteLine($"Removed app '{AppOrServiceName}'");
}
internal override void ExecuteForService()
{
var svcInfo = Context.Configuration.GetServiceInfo(AppOrServiceName);
Context.Configuration.RemoveService(AppOrServiceName);
Context.Console.WriteLine($"Removed {svcInfo.ServiceType} service '{AppOrServiceName}'");
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// An attribute indicating a workflow that needs an existing Steeltoe Configuration.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RequiresInitializationAttribute : Attribute
{
}
}

Просмотреть файл

@ -1,26 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// An attribute that indicates a workflow that needs a configured deployment target.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RequiresTargetAttribute: RequiresInitializationAttribute
{
}
}

Просмотреть файл

@ -1,143 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to set the arguments of an application or service.
/// </summary>
[RequiresInitialization]
public class SetArgsExecutor : AppOrServiceExecutor
{
private readonly string _target;
private readonly string _args;
private readonly bool _force;
/// <summary>
/// A workflow to set the arguments for an application or service.
/// </summary>
/// <param name="appOrServiceName">Application or service name.</param>
/// <param name="args">Application or service arguments.</param>
/// <param name="force">Force replacement of existing arguments.</param>
public SetArgsExecutor(string appOrServiceName, string args, bool force = false)
: this(appOrServiceName, null, args, force)
{
}
/// <summary>
/// A workflow to set the arguments for an application or service.
/// If <code>target</code> is null, set the application or service arguments.
/// If <code>target</code> is not null, set the arguments for deploying the application or service.
/// </summary>
/// <param name="appOrServiceName">Application or service name.</param>
/// <param name="target">Deployment target name (can be null).</param>
/// <param name="args">Application or service arguments.</param>
/// <param name="force">Force replacement of existing arguments.</param>
public SetArgsExecutor(string appOrServiceName, string target, string args, bool force = false)
: base(appOrServiceName)
{
_target = target;
_args = args;
_force = force;
}
/// <summary>
/// Set the application arguments.
/// </summary>
internal override void ExecuteForApp()
{
if (_target == null)
{
ExecuteSetAppArgs();
}
else
{
ExecuteSetAppTargetArgs();
}
}
/// <summary>
/// Set the service arguments.
/// </summary>
internal override void ExecuteForService()
{
if (_target == null)
{
ExecuteSetServiceArgs();
}
else
{
ExecuteSetServiceTargetArgs();
}
}
private void ExecuteSetAppArgs()
{
var appName = AppOrServiceName;
var args = Context.Configuration.GetAppArgs(appName);
if (args != null && !_force)
{
throw new ToolingException($"'{appName}' app args already set to '{args}'");
}
Context.Configuration.SetAppArgs(appName, _args);
Context.Console.WriteLine($"Set '{appName}' app args to '{_args}'");
}
private void ExecuteSetAppTargetArgs()
{
var appName = AppOrServiceName;
var args = Context.Configuration.GetAppArgs(appName, _target);
if (args != null && !_force)
{
throw new ToolingException($"'{_target}' deploy args for '{appName}' app already set to '{args}'");
}
Context.Configuration.SetAppArgs(appName, _target, _args);
Context.Console.WriteLine($"Set '{_target}' deploy args for '{appName}' app to '{_args}'");
}
private void ExecuteSetServiceArgs()
{
var svcName = AppOrServiceName;
var svcInfo = Context.Configuration.GetServiceInfo(svcName);
var args = Context.Configuration.GetServiceArgs(svcName);
if (args != null && !_force)
{
throw new ToolingException($"'{svcName}' {svcInfo.ServiceType} service args already set to '{args}'");
}
Context.Configuration.SetServiceArgs(svcName, _args);
Context.Console.WriteLine($"Set '{svcName}' {svcInfo.ServiceType} service args to '{_args}'");
}
private void ExecuteSetServiceTargetArgs()
{
var svcName = AppOrServiceName;
var svcInfo = Context.Configuration.GetServiceInfo(svcName);
var args = Context.Configuration.GetServiceArgs(svcName, _target);
if (args != null && !_force)
{
throw new ToolingException(
$"'{_target}' deploy args for '{AppOrServiceName}' {svcInfo.ServiceType} service already set to '{args}'");
}
Context.Configuration.SetServiceArgs(AppOrServiceName, _target, _args);
Context.Console.WriteLine(
$"Set '{_target}' deploy args for '{AppOrServiceName}' {svcInfo.ServiceType} service to '{_args}'");
}
}
}

Просмотреть файл

@ -1,61 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to set the current deployment target.
/// </summary>
[RequiresInitialization]
public class SetTargetExecutor : Executor
{
private readonly string _target;
private readonly bool _force;
/// <summary>
/// Create a workflow to set the current deployment target.
/// </summary>
/// <param name="target">Deployment target name.</param>
/// <param name="force">Overwrite an existing deployment target.</param>
public SetTargetExecutor(string target, bool force = false)
{
_target = target;
_force = force;
}
/// <summary>
/// Set the current deployment target.
/// </summary>
/// <exception cref="ToolingException">If an error occurs setting the deployment target.</exception>
protected override void Execute()
{
Target tgt = Registry.GetTarget(_target);
if (!tgt.IsHealthy(Context))
{
if (!_force)
{
Context.Console.WriteLine("Fix errors above or re-run with '-F|--force'");
throw new ToolingException($"Target '{_target}' does not appear healthy");
}
Context.Console.WriteLine("Ignoring poor health report above :-(");
}
Context.Configuration.Target = _target;
Context.Console.WriteLine($"Target set to '{_target}'");
}
}
}

Просмотреть файл

@ -1,50 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to display the deployment status of applications and dependent services.
/// </summary>
[RequiresTarget]
public class StatusExecutor : GroupExecutor
{
/// <summary>
/// Create a workflow to display the deployment status of applications and dependent services.
/// </summary>
public StatusExecutor() : base(false)
{
}
/// <summary>
/// Print app status.
/// </summary>
/// <param name="app">App name.</param>
protected override void ExecuteForApp(string app)
{
var status = Context.Driver.GetAppStatus(app);
Context.Console.WriteLine($"{app} {status.ToString().ToLower()}");
}
/// <summary>
/// Print service status.
/// </summary>
/// <param name="service">Service name.</param>
protected override void ExecuteForService(string service)
{
var status = Context.Driver.GetServiceStatus(service);
Context.Console.WriteLine($"{service} {status.ToString().ToLower()}");
}
}
}

Просмотреть файл

@ -1,83 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Threading;
namespace Steeltoe.Tooling.Executors
{
/// <summary>
/// A workflow to undeploy applications and dependent services from the current target.
/// </summary>
[RequiresTarget]
public class UndeployExecutor : GroupExecutor
{
/// <summary>
/// Creates a workflow undeploy applications and dependent services from the current target.
/// </summary>
public UndeployExecutor() : base(true)
{
}
/// <summary>
/// Defers to base class then calls Driver.DeployTeardown.
/// </summary>
protected override void Execute()
{
base.Execute();
Context.Driver.DeployTeardown();
}
/// <summary>
/// Undeploys apps then blocks until all apps offline.
/// </summary>
/// <param name="apps">Apps to undeploy.</param>
protected override void ExecuteForApps(List<string> apps)
{
base.ExecuteForApps(apps);
WaitUntilAllTransitioned(apps, Context.Driver.GetAppStatus, Lifecycle.Status.Offline);
}
/// <summary>
/// Undeploys services then blocks until all apps offline.
/// </summary>
/// <param name="services">Services to undeploy.</param>
protected override void ExecuteForServices(List<string> services)
{
base.ExecuteForServices(services);
WaitUntilAllTransitioned(services, Context.Driver.GetServiceStatus, Lifecycle.Status.Offline);
}
/// <summary>
/// Undeploys an application to the current target.
/// </summary>
/// <param name="app">Application name.</param>
protected override void ExecuteForApp(string app)
{
Context.Console.WriteLine($"Undeploying app '{app}'");
new Lifecycle(Context, app).Undeploy();
}
/// <summary>
/// Undeploys a service to the current target.
/// </summary>
/// <param name="service">Service name.</param>
protected override void ExecuteForService(string service)
{
Context.Console.WriteLine($"Undeploying service '{service}'");
new Lifecycle(Context, service).Undeploy();
}
}
}

Просмотреть файл

@ -1,75 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
{
/// <summary>
/// Defines the interface for Steeltoe Tooling drivers. Drivers are responsible for application and service
/// deployment and for reporting the state of applications and services.
/// </summary>
public interface IDriver
{
/// <summary>
/// Called before apps and/or services are deployed.
/// </summary>
void DeploySetup();
/// <summary>
/// Called affter apps and/or services are undeployed.
/// </summary>
void DeployTeardown();
/// <summary>
/// Deploys the named application.
/// </summary>
/// <param name="app">The application name.</param>
/// <remarks>Implementations may return before the application is fully deployed.</remarks>
void DeployApp(string app);
/// <summary>
/// Undeploys the named application.
/// </summary>
/// <param name="app">The application name.</param>
/// <remarks>Implementations may return before the application is fully undeployed.</remarks>
void UndeployApp(string app);
/// <summary>
/// Returns the named application's lifecycle status.
/// </summary>
/// <param name="app">The application name.</param>
/// <returns>The named application's lifecycle status.</returns>
Lifecycle.Status GetAppStatus(string app);
/// <summary>
/// Deploys the named service.
/// </summary>
/// <param name="service">The service name.</param>
/// <remarks>Implementations may return before the service is fully deployed.</remarks>
void DeployService(string service);
/// <summary>
/// Undeploys the named service.
/// </summary>
/// <param name="service">The service name.</param>
/// <remarks>Implementations may return before the service is fully undeployed.</remarks>
void UndeployService(string service);
/// <summary>
/// Returns the named service's lifecycle status.
/// </summary>
/// <param name="service">The service name.</param>
/// <returns>The named service's lifecycle status.</returns>
Lifecycle.Status GetServiceStatus(string service);
}
}

Просмотреть файл

@ -1,44 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
{
/// <summary>
/// Represents errors when referencing items that do not exist in the Steeltoe Tooling project configuration.
/// </summary>
public class ItemDoesNotExistException : ToolingException
{
/// <summary>
/// Item name.
/// </summary>
public string Name { get; }
/// <summary>
/// Item description.
/// </summary>
public string Description { get; }
/// <summary>
/// Creates a new ItemDoesNotExistException.
/// </summary>
/// <param name="name">Item name.</param>
/// <param name="description">Item description.</param>
public ItemDoesNotExistException(string name, string description) : base(
$"{char.ToUpper(description[0]) + description.Substring(1)} '{name}' does not exist")
{
Name = name;
Description = description;
}
}
}

Просмотреть файл

@ -1,44 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
{
/// <summary>
/// Represents errors when an item unexpectedly exists in the Steeltoe Tooling project configuration.
/// </summary>
public class ItemExistsException : ToolingException
{
/// <summary>
/// Item name.
/// </summary>
public string Name { get; }
/// <summary>
/// Item description.
/// </summary>
public string Description { get; }
/// <summary>
/// Creates a new ItemDoesNotExistException.
/// </summary>
/// <param name="name">Item name.</param>
/// <param name="description">Item description.</param>
public ItemExistsException(string name, string description) : base(
$"{char.ToUpper(description[0]) + description.Substring(1)} '{name}' already exists")
{
Name = name;
Description = description;
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
namespace Steeltoe.Tooling
{
/// <summary>
@ -52,8 +54,6 @@ namespace Steeltoe.Tooling
private readonly string _name;
private readonly DriverBridge _bridge;
/// <summary>
/// Creates a new lifecycle for the named application or application service.
/// </summary>
@ -61,17 +61,7 @@ namespace Steeltoe.Tooling
/// <param name="name">Application or application service name.</param>
public Lifecycle(Context context, string name)
{
var driver = context.Driver;
_name = name;
if (context.Configuration.GetApps().Contains(name))
{
_bridge = new AppDriverBridge(driver);
}
else
{
_bridge = new ServiceDriverBridge(driver);
}
}
/// <summary>
@ -80,25 +70,10 @@ namespace Steeltoe.Tooling
/// <returns></returns>
public Status GetStatus()
{
return _bridge.GetStatus(_name);
}
/// <summary>
/// Undeploy an application or application service in the context of this lifecycle.
/// </summary>
public void Undeploy()
{
GetState().Undeploy(_name, _bridge);
}
/// <summary>
/// Deploy an application or application service in the context of this lifecycle.
/// </summary>
public void Deploy()
{
GetState().Deploy(_name, _bridge);
throw new NotImplementedException();
}
/*
private State GetState()
{
var status = GetStatus();
@ -117,100 +92,68 @@ namespace Steeltoe.Tooling
}
}
abstract class State
private abstract class State
{
internal virtual void Deploy(string name, DriverBridge bridge)
{
throw new ToolingException($"Cannot deploy '{name}' because it is {this}");
}
internal virtual void Undeploy(string name, DriverBridge bridge)
{
throw new ToolingException($"Cannot undeploy '{name}' because it is {this}");
}
}
class OfflineState : State
private class OfflineState : State
{
internal override void Deploy(string name, DriverBridge bridge)
{
bridge.Deploy(name);
}
}
class StartingState : State
internal override void Undeploy(string name, DriverBridge bridge)
{
}
class OnlineState : State
public override string ToString()
{
return "offline";
}
}
private class StartingState : State
{
public override string ToString()
{
return "starting";
}
}
private class OnlineState : State
{
internal override void Deploy(string name, DriverBridge bridge)
{
}
internal override void Undeploy(string name, DriverBridge bridge)
{
bridge.Undeploy(name);
}
}
class StoppingState : State
public override string ToString()
{
return "online";
}
}
abstract class DriverBridge
private class StoppingState : State
{
protected readonly IDriver Driver;
internal DriverBridge(IDriver driver)
public override string ToString()
{
Driver = driver;
}
internal abstract Status GetStatus(string name);
internal abstract void Deploy(string name);
internal abstract void Undeploy(string name);
}
class AppDriverBridge : DriverBridge
{
internal AppDriverBridge(IDriver driver) : base(driver)
{
}
internal override Status GetStatus(string name)
{
return Driver.GetAppStatus(name);
}
internal override void Deploy(string name)
{
Driver.DeployApp(name);
}
internal override void Undeploy(string name)
{
Driver.UndeployApp(name);
}
}
class ServiceDriverBridge : DriverBridge
{
internal ServiceDriverBridge(IDriver driver) : base(driver)
{
}
internal override Status GetStatus(string name)
{
return Driver.GetServiceStatus(name);
}
internal override void Deploy(string name)
{
Driver.DeployService(name);
}
internal override void Undeploy(string name)
{
Driver.UndeployService(name);
return "stopping";
}
}
*/
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,16 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// Defines the interface to receive alerts that the Steeltoe Tooling project configuration has changed.
/// A model of a Docker deployment.
/// </summary>
public interface IConfigurationListener
public class DeploymentConfiguration
{
/// <summary>
/// Called when the Steeltoe Project configuration has changed.
/// Deployment name.
/// </summary>
void ConfigurationChangeEvent();
[YamlMember(Alias = "configuration")]
public string Name { get; set; }
/// <summary>
/// Project to be deployed.
/// </summary>
[YamlMember(Alias = "project")]
public Project Project { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,50 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// Helper for building a deployment configuration.
/// </summary>
public class DeploymentConfigurationBuilder
{
private readonly Context _context;
/// <summary>
/// Create a DeploymentConfigurationBuilder for the specified directory.
/// </summary>
public DeploymentConfigurationBuilder(Context context)
{
_context = context;
}
/// <summary>
/// Returns a deployment configuration.
/// </summary>
/// <returns>deployment configuration model</returns>
public DeploymentConfiguration BuildDeployment()
{
var name = Path.GetFileName(_context.WorkingDirectory);
var deployment = new DeploymentConfiguration
{
Name = name,
Project = new ProjectBuilder(_context, Path.Join(_context.WorkingDirectory, $"{name}.csproj"))
.BuildProject()
};
return deployment;
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// A model of a DotNet project.
/// </summary>
public class Project
{
/// <summary>
/// Project name.
/// </summary>
[YamlMember(Alias = "name")]
public string Name
{
get => _name;
set => _name = value.ToLower();
}
private string _name;
/// <summary>
/// Project file path.
/// </summary>
[YamlMember(Alias = "file")]
public string File { get; set; }
/// <summary>
/// Project framework.
/// </summary>
[YamlMember(Alias = "framework")]
public string Framework { get; set; }
/// <summary>
/// Docker image.
/// </summary>
[YamlMember(Alias = "image")]
public string Image { get; set; }
/// <summary>
/// Network ports.
/// </summary>
[YamlMember(Alias = "protocols")]
public List<Protocol> Protocols { get; set; }
/// <summary>
/// Project service dependencies to be deployed.
/// </summary>
[YamlMember(Alias = "services")]
public List<Service> Services { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,178 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.Extensions.Logging;
using YamlDotNet.RepresentationModel;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// Helper for building a Project.
/// </summary>
public class ProjectBuilder
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<ProjectBuilder>();
private Context _context;
private readonly string _projectFile;
private readonly string _launchSettingsFile;
private XmlDocument _projectDoc;
/// <summary>
/// Project file.
/// </summary>
public string ProjectFile { get; set; }
/// <summary>
/// Create a ProjectBuilder for the specified project file.
/// </summary>
public ProjectBuilder(Context context, string projectFile)
{
_context = context;
_projectFile = projectFile;
_launchSettingsFile = Path.Join(Path.GetDirectoryName(projectFile), "Properties", "launchSettings.json");
}
/// <summary>
/// Returns a Project representation of the ProjectFile.
/// </summary>
/// <returns>project model</returns>
public Project BuildProject()
{
Logger.LogDebug($"loading project file: {_projectFile}");
if (!File.Exists(_projectFile))
{
throw new ToolingException($"project file not found: {_projectFile}");
}
_projectDoc = new XmlDocument();
_projectDoc.Load(_projectFile);
var project = new Project
{
Name = Path.GetFileNameWithoutExtension(_projectFile),
File = Path.GetFileName(_projectFile)
};
project.Framework = GetFramework();
if (_context.Registry.DotnetImages.TryGetValue(project.Framework, out var image))
{
project.Image = image;
}
else
{
throw new ToolingException($"no image for framework: {project.Framework}");
}
project.Protocols = GetProtocols();
project.Services = GetServices();
return project;
}
private string GetFramework()
{
XmlNodeList nodes = _projectDoc.SelectNodes("/Project/PropertyGroup/TargetFramework");
if (nodes.Count > 0)
{
return nodes[0].InnerText;
}
nodes = _projectDoc.SelectNodes("/Project/PropertyGroup/TargetFrameworks");
if (nodes.Count > 0)
{
return nodes[0].InnerText.Split(';')[0];
}
throw new ToolingException("could not determine framework");
}
private List<Protocol> GetProtocols()
{
var protocols = new List<Protocol>();
if (File.Exists(_launchSettingsFile))
{
Logger.LogDebug($"loading launch settings: {_launchSettingsFile}");
var yaml = new YamlStream();
using (var reader = new StreamReader(_launchSettingsFile))
{
yaml.Load(reader);
}
var root = (YamlMappingNode) yaml.Documents[0].RootNode;
var profiles = (YamlMappingNode) root.Children[new YamlScalarNode("profiles")];
foreach (var entry in profiles.Children)
{
var profile = (YamlMappingNode) entry.Value;
if (profile.Children.ContainsKey(new YamlScalarNode("applicationUrl")))
{
var urlSpec = profile.Children[new YamlScalarNode("applicationUrl")];
var urls = $"{urlSpec}".Split(';');
foreach (var url in urls)
{
var uri = new Uri(url);
protocols.Add(new Protocol(uri.Scheme, uri.Port));
}
}
}
}
// ensure a default protocol
if (protocols.Count == 0)
{
protocols.Add(new Protocol("http", 8080));
}
protocols.Sort();
return protocols;
}
private List<Service> GetServices()
{
List<Service> services = new List<Service>();
foreach (var svcspec in _context.Registry.ServiceSpecifications)
{
foreach (var nuget in svcspec.NuGets)
{
var xpath = $"/Project/ItemGroup/PackageReference[@Include='{nuget}']";
if (_projectDoc.SelectNodes(xpath).Count == 0)
{
xpath = $"/Project/ItemGroup/Reference[@Include='{nuget}']";
if (_projectDoc.SelectNodes(xpath).Count == 0)
{
continue;
}
}
var service = new Service()
{
Name = svcspec.Type,
Image = svcspec.Image,
Port = svcspec.Port
};
services.Add(service);
}
}
if (services.Count == 0)
{
return null;
}
return services;
}
}
}

Просмотреть файл

@ -0,0 +1,66 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// A network port.
/// </summary>
public class Protocol : IComparable
{
/// <summary>
/// Service protocol.
/// </summary>
[YamlMember(Alias = "name")]
public string Name { get; }
/// <summary>
/// Service port.
/// </summary>
[YamlMember(Alias = "port")]
public int Port { get; }
/// <summary>
/// Create a new Protocol.
/// </summary>
/// <param name="name">Protocol name.</param>
/// <param name="port">Protocol port.</param>
public Protocol(string name, int port)
{
Name = name;
Port = port;
}
/// <summary>
/// Returns a comparison of the Protocols' names, and if equal, a comparison of the ports.
/// </summary>
/// <param name="obj">Protocol against which to compare.</param>
/// <returns>&lt;0, 0, &gt;0.</returns>
public int CompareTo(object obj)
{
var svc = (Protocol) obj;
var compare = Name.CompareTo(svc.Name);
if (compare != 0)
{
return compare;
}
return Port.CompareTo(svc.Port);
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -14,38 +14,35 @@
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// Specifies a service.
/// A model of a project service dependency.
/// </summary>
public class ServiceTypeInfo
public class Service
{
/// <summary>
/// Service name.
/// </summary>
[YamlMember(Alias = "name")]
public string Name { get; set; }
public string Name
{
get => _name;
set => _name = value.ToLower();
}
private string _name;
/// <summary>
/// Docker image.
/// </summary>
[YamlMember(Alias = "image")]
public string Image { get; set; }
/// <summary>
/// Service port.
/// </summary>
[YamlMember(Alias = "port")]
public int Port { get; set; }
/// <summary>
/// Service description.
/// </summary>
[YamlMember(Alias = "description")]
public string Description { get; set; }
/// <summary>
/// Returns a human-readable representation of this ServiceTypeInfo.
/// </summary>
/// <returns>A human readable string.</returns>
public override string ToString()
{
return $"ServiceTypeinfo[name={Name},port={Port},desc=\"{Description}\"]";
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,32 +12,38 @@
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
{
/// <summary>
/// An application service, such as a database, that can be deployed.
/// </summary>
public class ServiceInfo
{
/// <summary>
/// Service name.
/// </summary>
public string Service { get; }
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// A model of a service specification.
/// </summary>
public class ServiceSpecification
{
/// <summary>
/// Service type.
/// </summary>
public string ServiceType { get; }
[YamlMember(Alias = "type")]
public string Type { get; set; }
/// <summary>
/// Creates a new ServiceInfo instance.
/// Docker image.
/// </summary>
/// <param name="service">Service name.</param>
/// <param name="serviceType">Service type.</param>
public ServiceInfo(string service, string serviceType)
{
Service = service;
ServiceType = serviceType;
}
[YamlMember(Alias = "image")]
public string Image { get; set; }
/// <summary>
/// Service port.
/// </summary>
[YamlMember(Alias = "port")]
public int Port { get; set; }
/// <summary>
/// Nugets.
/// </summary>
[YamlMember(Alias = "nugets")]
public List<string> NuGets { get; set; }
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -14,194 +14,45 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Steeltoe.Tooling.Drivers.CloudFoundry;
using Steeltoe.Tooling.Drivers.Docker;
using Steeltoe.Tooling.Drivers.Dummy;
using Steeltoe.Tooling.Drivers.Kubernetes;
using Steeltoe.Tooling.Models;
using YamlDotNet.Serialization;
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
namespace Steeltoe.Tooling
{
/// <summary>
/// Represents a Steeltoe Tooling projects available application service types and deployment targets.
/// Tooling registry.
/// </summary>
public class Registry
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<Registry>();
/// <summary>
/// Represents the Registry's configuration.
/// Docker images for dotnet SDKs.
/// </summary>
public class Configuration
{
/// <summary>
/// Available application service types.
/// </summary>
[YamlMember(Alias = "serviceTypes")]
public Dictionary<string, ServiceTypeInfo> ServiceTypes { get; set; } =
new Dictionary<string, ServiceTypeInfo>();
public Dictionary<string, string> DotnetImages { get; private set; }
/// <summary>
/// Available deployment targets.
/// Services.
/// </summary>
[YamlMember(Alias = "targets")]
public Dictionary<string, TargetConfiguration> TargetConfigurations { get; set; } =
new Dictionary<string, TargetConfiguration>();
public List<ServiceSpecification> ServiceSpecifications { get; private set; }
/// <summary>
/// Defines a new application service type.
/// Load the registry from the specified directory.
/// </summary>
/// <param name="name">Application service type name.</param>
/// <param name="port">Application service port.</param>
/// <param name="description">Application service description.</param>
public void DefineServiceType(string name, int port, string description)
/// <param name="directory"></param>
public void Load(string directory)
{
ServiceTypes[name] = new ServiceTypeInfo {Port = port, Description = description};
}
/// <summary>
/// Defines a new deployment target.
/// </summary>
/// <param name="target">Deployment target name.</param>
/// <param name="description">Deployment target description.</param>
public void DefineTarget(string target, string description)
{
TargetConfigurations[target] = new TargetConfiguration {Description = description};
}
/// <summary>
/// Defines a new application service type property for a deployment target.
/// </summary>
/// <param name="target">Deployment target name.</param>
/// <param name="serviceType">Application service type name.</param>
/// <param name="propertyName">Application service type property name.</param>
/// <param name="propertyValue">Application service type property value.</param>
public void DefineTargetServiceTypeProperty(
string target,
string serviceType,
string propertyName,
string propertyValue)
{
if (!TargetConfigurations.ContainsKey(target))
{
TargetConfigurations[target] = new TargetConfiguration();
}
var targetCfg = TargetConfigurations[target];
if (!targetCfg.ServiceTypeProperties.ContainsKey(serviceType))
{
targetCfg.ServiceTypeProperties[serviceType] = new Dictionary<string, string>();
}
targetCfg.ServiceTypeProperties[serviceType][propertyName] = propertyValue;
TargetConfigurations[target] = targetCfg;
}
}
private static Configuration _configuration = new Configuration();
/// <summary>
/// Returns available deployment targets.
/// </summary>
public static List<string> Targets => _configuration.TargetConfigurations.Keys.ToList();
static Registry()
{
// testing service type
if (Settings.DummiesEnabled)
{
Logger.LogDebug("loading dummy registry");
var dummyCfg = new Configuration();
var dummySvcType = new ServiceTypeInfo {Port = 0, Description = "A Dummy Service"};
dummyCfg.ServiceTypes.Add("dummy-svc", dummySvcType);
var dummyTarget = new TargetConfiguration();
dummyTarget.Description = "A Dummy Target";
dummyCfg.TargetConfigurations.Add("dummy-target", dummyTarget);
AddRegistryConfiguration(dummyCfg);
}
// default service types
var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "steeltoe.rc",
"registry.yaml");
Logger.LogDebug($"loading registry from {path}");
Logger.LogDebug($"loading registry: {directory}");
var deserializer = new DeserializerBuilder().Build();
using (var reader = new StreamReader(path))
using (var reader = new StreamReader(Path.Join(directory, "dotnet.yml")))
{
var defaultCfg = deserializer.Deserialize<Configuration>(reader);
AddRegistryConfiguration(defaultCfg);
}
DotnetImages = deserializer.Deserialize<Dictionary<string, string>>(reader);
}
/// <summary>
/// Returns available application service types.
/// </summary>
/// <returns>Available application service types.</returns>
public static List<string> GetServiceTypes()
using (var reader = new StreamReader(Path.Join(directory, "dependencies.yml")))
{
return _configuration.ServiceTypes.Keys.ToList();
}
/// <summary>
/// Returns the application service type information for the named type.
/// </summary>
/// <param name="serviceType">Application service type name.</param>
/// <returns></returns>
public static ServiceTypeInfo GetServiceTypeInfo(string serviceType)
{
ServiceTypeInfo svcTypeInfo;
if (_configuration.ServiceTypes.TryGetValue(serviceType, out svcTypeInfo))
{
svcTypeInfo.Name = serviceType;
return svcTypeInfo;
}
return null;
}
/// <summary>
/// Returns the named deployment target.
/// </summary>
/// <param name="target">Deployment target name.</param>
/// <returns>Named deployment target.</returns>
/// <exception cref="ToolingException">Thrown if there is no such deployment target.</exception>
public static Target GetTarget(string target)
{
TargetConfiguration targetCfg;
if (_configuration.TargetConfigurations.TryGetValue(target, out targetCfg))
{
targetCfg.Name = target;
switch (targetCfg.Name)
{
case "cloud-foundry":
return new CloudFoundryTarget(targetCfg);
case "docker":
return new DockerTarget(targetCfg);
case "kubernetes":
return new KubernetesTarget(targetCfg);
case "dummy-target":
return new DummyTarget(targetCfg);
}
}
throw new ToolingException($"Unknown target '{target}'");
}
private static void AddRegistryConfiguration(Configuration configuration)
{
foreach (var svcTypeEntry in configuration.ServiceTypes)
{
svcTypeEntry.Value.Name = null;
_configuration.ServiceTypes[svcTypeEntry.Key] = svcTypeEntry.Value;
}
foreach (var targetCfgEntry in configuration.TargetConfigurations)
{
targetCfgEntry.Value.Name = null;
_configuration.TargetConfigurations[targetCfgEntry.Key] = targetCfgEntry.Value;
ServiceSpecifications = deserializer.Deserialize<List<ServiceSpecification>>(reader);
}
}
}

Просмотреть файл

@ -1,29 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Steeltoe.Tooling.Scanners
{
/// <summary>
/// A scanner for applications.
/// </summary>
public class AppScanner
{
/// <summary>
/// Scans for applications in the specified path.
/// </summary>
/// <param name="path">Path at which to scan.</param>
/// <returns></returns>
public List<AppInfo> Scan(string path)
{
List<AppInfo> apps = new List<AppInfo>();
foreach (var project in Directory.GetFiles(path).Where(f => f.EndsWith(".csproj")))
{
var app = new AppInfo(Path.GetFileNameWithoutExtension(project));
apps.Add(app);
}
return apps;
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -25,25 +25,5 @@ namespace Steeltoe.Tooling
/// Whether debugging has been enabled.
/// </summary>
public static bool DebugEnabled { get; set; }
/// <summary>
/// Whether verbose console output has been enabled.
/// </summary>
public static bool VerboseEnabled { get; set; }
/// <summary>
/// Whether the dummy deployment target and dummy services have been enabled. Used for debugging and development.
/// </summary>
public static bool DummiesEnabled { get; set; }
/// <summary>
/// The maximum number of checks when waiting for an application or application service lifecycle transition.
/// </summary>
public static int MaxChecks { get; set; } = -1;
static Settings()
{
DummiesEnabled = File.Exists(".steeltoe.dummies");
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ namespace Steeltoe.Tooling
public abstract class Shell
{
/// <summary>
/// Implemetations return the result of running a command.
/// Implementations return the result of running a command.
/// </summary>
/// <param name="command">System command.</param>
/// <param name="args">Command arguments.</param>

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Просмотреть файл

@ -3,7 +3,7 @@
<PropertyGroup>
<Title>Steeltoe Developer Tooling Library</Title>
<Description>A new way of interacting with your applications, services and service instances</Description>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<PackageIconUrl>https://steeltoe.io/images/transparent.png</PackageIconUrl>
<PackageProjectUrl>https://steeltoe.io</PackageProjectUrl>
@ -16,6 +16,7 @@
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="$(McMasterExtensionsCommandLineUtilsVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsVersion)" />
<PackageReference Include="StringTemplate4" Version="$(StringTemplate4Version)" />
<PackageReference Include="YamlDotNet" Version="$(YamlDotNetVersion)" />
</ItemGroup>
<ItemGroup>
@ -23,7 +24,4 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Drivers" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,79 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
{
/// <summary>
/// Represents a deployment target.
/// </summary>
public abstract class Target
{
/// <summary>
/// Deployment target configuration.
/// </summary>
public TargetConfiguration Configuration { get; }
/// <summary>
/// Deployment target name.
/// </summary>
public string Name => Configuration.Name;
/// <summary>
/// Deployment target description.
/// </summary>
public string Description => Configuration.Description;
/// <summary>
/// Creates a new Target.
/// </summary>
/// <param name="configuration">Deployment target configuration.</param>
protected Target(TargetConfiguration configuration)
{
Configuration = configuration;
}
/// <summary>
/// Return the deployment target driver.
/// </summary>
/// <param name="context">Steeltoe Tooling project context.</param>
/// <returns></returns>
public abstract IDriver GetDriver(Context context);
/// <summary>
/// Tests if the deployment target is healthy. E.g., is the target available.
/// </summary>
/// <param name="context">Steeltoe Tooling project context.</param>
/// <returns></returns>
public abstract bool IsHealthy(Context context);
/// <summary>
/// Return a human-readable representation of this Target.
/// </summary>
/// <returns>A human readable representation.</returns>
public override string ToString()
{
return $"Target[name={Name},desc=\"{Description}\"]";
}
/// <summary>
/// Return the named property value.
/// </summary>
/// <param name="name">Property name.</param>
/// <returns>Property value.</returns>
public string GetProperty(string name)
{
return Configuration.Properties[name];
}
}
}

Просмотреть файл

@ -1,48 +0,0 @@
// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Collections.Generic;
using YamlDotNet.Serialization;
namespace Steeltoe.Tooling
{
/// <summary>
/// Rerpresents the configuration of a deployment target.
/// </summary>
public class TargetConfiguration
{
/// <summary>
/// Deployment target name.
/// </summary>
[YamlMember(Alias = "name")] public string Name { get; set; }
/// <summary>
/// Deployment target description.
/// </summary>
[YamlMember(Alias = "description")] public string Description { get; set; }
/// <summary>
/// Deployment target properties.
/// </summary>
[YamlMember(Alias = "properties")]
public Dictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Deployment target application service type properties.
/// </summary>
[YamlMember(Alias = "serviceTypeProperties")]
public Dictionary<string, Dictionary<string, string>> ServiceTypeProperties { get; set; } =
new Dictionary<string, Dictionary<string, string>>();
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,25 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Steeltoe.Tooling
namespace Steeltoe.Tooling.Templates
{
/// <summary>
/// An application that can be deployed.
/// Template abstraction.
/// </summary>
public class AppInfo
public interface ITemplate
{
/// <summary>
/// Application name.
/// Binds the object to the named template variable.
/// </summary>
public string App { get; }
/// <param name="name"></param>
/// <param name="obj"></param>
void Bind(string name, object obj);
/// <summary>
/// Creates a new AppInfo for the specified applicaition.
/// Returns the rendered template.
/// </summary>
/// <param name="app">Application name.</param>
public AppInfo(string app)
{
App = app;
}
/// <returns></returns>
string Render();
}
}

Просмотреть файл

@ -0,0 +1,72 @@
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.IO;
using System.Reflection;
using Antlr4.StringTemplate;
namespace Steeltoe.Tooling.Templates
{
/// <summary>
/// Acts as a facade for template implementations.
/// </summary>
public class TemplateManager
{
private static readonly object TemplaterLock = new object();
/// <summary>
/// Gets the named template.
/// </summary>
/// <param name="name">Template name.</param>
/// <returns></returns>
public static ITemplate GetTemplate(string name)
{
var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"steeltoe.rc", "templates", name);
var template = File.ReadAllText(path);
try
{
lock (TemplaterLock) // AntlrStringTemplate doesn't seem to be thread safe
{
return new AntlrStringTemplate(template);
}
}
catch (Exception e)
{
throw new ToolingException($"failed to load template: {name} [{e.Message}]");
}
}
class AntlrStringTemplate : ITemplate
{
private Template _template;
internal AntlrStringTemplate(string template)
{
_template = new Template(template);
}
public void Bind(string name, object obj)
{
_template.Add(name, obj);
}
public string Render()
{
return _template.Render();
}
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2018 the original author or authors.
// Copyright 2020 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Просмотреть файл

@ -0,0 +1,28 @@
- type: mssql
image: steeltoeoss/mssql-amd64-linux
port: 1433
nugets:
- Microsoft.EntityFrameworkCore.SqlServer
- type: mysql
image: steeltoeoss/mysql:5.7
port: 3306
nugets:
- MySql.Data
- Pomelo.EntityFrameworkCore.MySql
- type: pgsql
image: steeltoeoss/postgresql:10.8
port: 5432
nugets:
- Npgsql
- Npgsql.EntityFrameworkCore.PostgreSQL
- type: rabbitmq
image: steeltoeoss/rabbitmq:3.7
port: 5672
nugets:
- RabbitMQ.Client
- type: redis
image: steeltoeoss/redis-amd64-linux:4.0.11
port: 6379
nugets:
- Microsoft.Extensions.Caching.Redis
- Microsoft.Extensions.Caching.StackExchangeRedis

Просмотреть файл

@ -0,0 +1,4 @@
netcoreapp2.1: mcr.microsoft.com/dotnet/core/sdk:2.1
netcoreapp2.2: mcr.microsoft.com/dotnet/core/sdk:2.2
netcoreapp3.1: mcr.microsoft.com/dotnet/core/sdk:3.1

Просмотреть файл

@ -0,0 +1,4 @@
FROM <image>
WORKDIR /<project.Name>
RUN mkdir -p /usr/local/share/dotnet/sdk/NuGetFallbackFolder
CMD ["dotnet", "watch", "run", "--urls", "<project.Protocols:{protocol |<protocol.Name>://0.0.0.0:<protocol.Port>}; separator=";">"]

Просмотреть файл

@ -0,0 +1,12 @@
version: "3.7"
services:
<project.Name>:
build: .
ports:
<project.Protocols: {protocol |- "<protocol.Port>:<protocol.Port>"}; separator="\n">
volumes:
- .:/<project.Name>
<project.Services: {svc |<svc.Name>:
image: <svc.Image>
ports:
- <svc.Port>}; separator="\n">

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше