bluemixgaragelondon / cf-blue-green-deploy Goto Github PK
View Code? Open in Web Editor NEWCloud Foundry CLI plugin for zero downtime deploys
License: Apache License 2.0
Cloud Foundry CLI plugin for zero downtime deploys
License: Apache License 2.0
This has been observed by code inspection.
I have:
an app
two domains:
a route from the private domain containing a path:
cf create-route my-space private-domain --path some-path
a mapping of the above route to my app
When deploying with the blue-green-deploy plugin the new app created has the same routes as the original app.
The route with the path is not mapped to the app. Instead, a route to just the private-domain
is created and mapped, resulting in incorrect routing behaviour.
Thanks for such a useful plugin! I have a long-running smoke test script that writes to stdout as it progresses. It seems that BGD captures the output as the smoke test is running and then displays it in its entirety only when the script has completed. It would be nice to see the output in real time. I'm new to Go, but I believe this is possible and would be willing to take a crack at it if it's something you'd consider merging.
If you have multiple applications in your manifest, e.g.:
---
applications:
- name: app_1
- name: app_2
And attempt to run the following command:
cf bgd app_1
You will get the following output:
Using manifest file /.../manifest.yml
Could not unmap route - App app_1-new not found
And that's it.
This is because when you have multiple applications in the manifest, pushing with push <app_name>
does not indicate the name that should be used on CF, but rather the name of the application that should be pushed. If it can't find it, it appears to shrug and report OK.
I would expect the BGD plugin to either: work around this and do a BGD of the single app I've requested, or fail-fast and tell me that it's not supported.
It's possible this is also an issue with the CF CLI not returning a non-zero exit code if it can't find the application requested in the manifest.
Hi there!
I noticed that bgd is ignoring the instances, memory and disk_quota from the manifest.yml file.
My app is running on PCF currently with 3 Instances, 1G memory and 1G disk.
If I try to redeploy with bgd over this app the deploy do not scale with the new resources.
If there is no app running, the deploy uses the data from the manifest.yml creating a app with the right resources.
My manifest.yml file:
applications:
- buildpack: staticfile_buildpack
disk_quota: 2G
env:
GRANT_TYPE: password
RESOURCE_URL: https://test.com
SKIP_SSL_VALIDATION: true
SSO_AUTO_APROVED_SCOPES: open.id, todo.read
SSO_IDENTITY_PROVIDERS: SSO
SSO_REDIRECT_URIS: https://test.com/
SSO_SCOPE: open.id, todo.read
instances: 4
memory: 2G
name: app-devops
random-route: false
services:
- config-server
Here the output from the command trying to redeploy the app:
# cf bgd app-name -f manifest.yml -smoke-test smoketest.sh
Deleting app app-name-old in org Org / space devops as devops...
OK
Using manifest file manifest.yml
Creating app app-name-new in org Org / space devops as devops...
OK
Using route app-name-new.test.com
Binding app-name-new.test.com to app-name-new...
OK
Uploading app-name-new...
Uploading app files from: /home/jenkins-slave/workspace/deploy-module
Uploading 477.6K, 66 files
Done uploading
OK
Binding service sbil-config-server to app app-name-new in org Org / space devops as devops...
OK
Starting app app-name-new in org Org / space devops as devops...
Downloading staticfile_buildpack...
Downloaded staticfile_buildpack
Creating container
Successfully created container
Downloading app package...
Downloaded app package (7.2M)
-----> Staticfile Buildpack version 1.4.21
-----> Installing nginx
Using nginx version 1.13.8
-----> Installing nginx 1.13.8
Copy [/tmp/buildpacks/4797a036f87bb3928bb164c574a43e2d/dependencies/3292a1fdf05213ded5bd38c322c33b1c/nginx-1.13.8-linux-x64-9585c5f4.tgz]
-----> Root folder /tmp/app
-----> Copying project files into public
-----> Configuring nginx
Exit status 0
Uploading droplet, build artifacts cache...
Uploading build artifacts cache...
Uploading droplet...
Uploaded build artifacts cache (218B)
Uploaded droplet (9.9M)
Successfully destroyed container
Uploading complete
Stopping instance c5e39b2b-46b6-43a1-90ab-4bcddd71a514
Destroying container
3 of 3 instances running
App started
OK
App app-name-new was started using this command `$HOME/boot.sh`
Showing health and status for app app-name-new in org Org / space devops as devops...
OK
requested state: started
instances: 3/3
usage: 1G x 3 instances
urls: app-name-new.test.com
last uploaded: Fri May 4 20:26:59 UTC 2018
stack: cflinuxfs2
buildpack: staticfile_buildpack
state since cpu memory disk details
#0 running 2018-05-04 03:27:25 PM 0.0% 0 of 1G 0 of 1G
#1 running 2018-05-04 03:27:26 PM 0.0% 0 of 1G 0 of 1G
#2 running 2018-05-04 03:27:25 PM 0.0% 0 of 1G 0 of 1G
ssh support is enabled for 'app-name'
ssh support is already enabled for 'app-name-new'
Removing route app-name-new.test.com from app app-name-new in org SvcsIT-AnEOrg / space devops as devops...
OK
Creating route app-name.test.com for org SvcsIT-AnEOrg / space devops as devops...
OK
Route app-name.test.com already exists
Adding route app-name.test.com to app app-name-new in org SvcsIT-AnEOrg / space devops as devops...
OK
Renaming app app-name to app-name-old in org SvcsIT-AnEOrg / space devops as devops...
OK
Renaming app app-name-new to app-name in org SvcsIT-AnEOrg / space devops as devops...
OK
Removing route app-name.test.com from app app-name-old in org SvcsIT-AnEOrg / space devops as devops...
OK
Is there a reason that the -old
suffixed app is left running after a successful deployment?
Would you accept a PR to automatically remove it when the deploy was successful?
Would you need the behaviour to be feature flagged with a new CLI argument?
Hi,
it would be great if the blue-green could have an additional step were the old green deployment is only stopped and relabeled to something like "previous".
So in case the new green is broken for example by business logic you could easy switch back to the previous version.
What do you think?
Thanks
I have my application deployed at testbed.artsquare.com
on Bluemix. When pushing with bgd
, the new application is routed as testbed-new.mybluemix.net
--not a big issue, but potentially a gotcha for some. However, bgd
then tries to map the new application to testbed.mybluemix.net
instead of testbed.artsquare.com
. Instead, it should copy the exact routes that are already applied.
Specifying the routes in a manifest is not practical because the application is first deployed to a staging environment with a completely different route setup.
When using Cloud Foundry v265 applications pushed with the blue-green-deploy plugin suffer downtime of up to 60 seconds. The steps to reproduce listed below demonstrate this is not actually caused by your plugin, but I am raising this issue because you are affected by it. When I find the Cloud Foundry component responsible I will raise it with them as well.
Update: We have tracked this down to the route-emitter and have raised an issue with its maintainers: https://github.com/cloudfoundry/route-emitter/issues/8. A fix is in diego-release v1.22.0. The earliest cf-release that includes this fix is v268.
We have deployed open source Cloud Foundry v265, upgrading from v257. We fully automate the deployment of applications using the blue-green-deployment plugin. There was zero downtime with CF v257, but now with CF v265 there is up to 60 seconds where requests to the app are responded to with a status code of 404.
This can be reproduced with all versions of the plugin, but we use scripting because the root cause is not this plugin. It seems it is a race condition in Cloud Foundry:
Deploy Cloud Foundry v265
Deploy an application
Set up a curl
to monitor the app:
while true; do curl -s -o /dev/null -w "%{http_code} " https://${APP_NAME}.${APP_DOMAIN} -k; date; sleep 1; done | tee /tmp/bgd.out
Do a blue-green deploy using this example script.
You should see 404s returned after the unmapping of the route from the old application for up to 60 seconds.
Add a sleep of 60 seconds before the unmapping of the route from the old app and the problem goes away.
In our setup the route-emitter emits registration and unregistration messages via NATS every 20 seconds and does a bulk update every 60 seconds. I believe this is representative of most deployments. Because the downtime is always less than 60 seconds I believe the state in BBS is correct and on the bulk update the problem gets fixed. Therefore, the route-emitter is somehow unregistering the route from the new app instead of the old app.
Update: I've confirmed by tailing the logs of the GoRouter that the route is definitely unregistered from the new app, when it should be unregistered from the old app.
cf-release v265
diego-release v1.19.0
All versions of this plugin
CF CLI 6.26
Does it keep environment variables provided outside the manifest.yml?
I mean, provided right in the web console...
Thank you.
Would you be able to release statically linked binaries for Linux so that we can use this plugin from a container that is based on Alpine Linux?
We use cf-cli with Alpine in our deployment pipeline because it has a minimal amount of dependencies to maintain. Alpine is based on musl-libc rather than glibc, so it's unable to run dynamically linked libraries.
For reference cf-cli made a similar change last year in cloudfoundry/cli#808. Although it's also worth noting that they had some problems with specific Go versions detailed in cloudfoundry/cli#763.
I'm unclear about the exact change that's required. If I build locally from Darwin using Go 1.7 then file artefacts/blue-green-deploy.linux64
confirms that it is statically linked.
Whenever I try to install this plugin, I get the following error:
Looking up 'blue-green-deploy' from repository 'CF-Community'
10093904 bytes downloaded...
Installing plugin /tmp/ filename=blue-green-deploy.osx...
FAILED
exit status 2
I can successfully install other plugins from the CF-Community repo. I checked since my normal culprit is our corporate proxy but that doesn't seem to be the case this time.
I am running Mac OSX 10.10.5.
While attempting pushing Blue-Green with cf-push-blue-green task, following exception are raised at step of binding services to app:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':cf-push-blue-green-1'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:242)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:317)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:309)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:185)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:95)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:235)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:224)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:121)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:77)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:102)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:96)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:612)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:567)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:96)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:57)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:122)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:46)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$ExecuteTasks.run(DefaultGradleLauncher.java:253)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:317)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:309)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:185)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:95)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:170)
at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:44)
at org.gradle.initialization.DefaultGradleLauncher$1.run(DefaultGradleLauncher.java:122)
at org.gradle.internal.work.DefaultWorkerLeaseService$2.execute(DefaultWorkerLeaseService.java:124)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:116)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:99)
at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:66)
at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$1.run(RunAsBuildOperationBuildActionRunner.java:43)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:317)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:309)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:185)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:95)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
at org.gradle.tooling.internal.provider.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:51)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:44)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:28)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:51)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:32)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:29)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:50)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:30)
at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:173)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:287)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:260)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:33)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:253)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:182)
at org.gradle.launcher.Main.doAction(Main.java:33)
at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:60)
at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:37)
at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
Caused by: org.cloudfoundry.client.v2.ClientV2Exception: CF-ServiceBrokerBadResponse(10001): Service broker error: UNKNOWN_ERROR - Failed to set credential permissions
at org.cloudfoundry.reactor.util.ErrorPayloadMapper.lambda$null$0(ErrorPayloadMapper.java:47)
at org.cloudfoundry.reactor.util.ErrorPayloadMapper.lambda$null$10(ErrorPayloadMapper.java:108)
at reactor.core.publisher.MonoThenMap$ThenMapMain.onNext(MonoThenMap.java:120)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:115)
at reactor.core.publisher.FluxUsing$UsingFuseableSubscriber.onNext(FluxUsing.java:351)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:103)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.onNext(FluxPeekFuseable.java:428)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:962)
at reactor.core.publisher.MonoReduceSeed$ReduceSeedSubscriber.onComplete(MonoReduceSeed.java:150)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:130)
at reactor.ipc.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:375)
at reactor.ipc.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:198)
at reactor.ipc.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:338)
at reactor.ipc.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:343)
at reactor.ipc.netty.channel.ChannelOperations.onHandlerTerminate(ChannelOperations.java:419)
at reactor.ipc.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:566)
at reactor.ipc.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:125)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1240)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1041)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.MonoPeek] :
reactor.core.publisher.Mono.checkpoint(Mono.java:1400)
org.cloudfoundry.reactor.client.v2.servicebindings.ReactorServiceBindingsV2.create(ReactorServiceBindingsV2.java:52)
org.cloudfoundry.operations.services.DefaultServices.requestCreateServiceBinding(DefaultServices.java:693)
org.cloudfoundry.operations.services.DefaultServices.createServiceBinding(DefaultServices.java:452)
org.cloudfoundry.operations.services.DefaultServices.lambda$bind$1(DefaultServices.java:130)
org.cloudfoundry.util.tuple.TupleUtils.lambda$function$8(TupleUtils.java:69)
reactor.core.publisher.MonoThenMap$ThenMapMain.onNext(MonoThenMap.java:120)
reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:962)
reactor.core.publisher.MonoThenMap$ThenMapMain$ThenMapInner.onNext(MonoThenMap.java:237)
reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:962)
reactor.core.publisher.MonoWhen$WhenCoordinator.signal(MonoWhen.java:249)
reactor.core.publisher.MonoWhen$WhenInner.onNext(MonoWhen.java:308)
reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:72)
reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:962)
reactor.core.publisher.MonoSingle$SingleSubscriber.onComplete(MonoSingle.java:169)
reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:739)
reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:511)
reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:491)
reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:484)
reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:245)
reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainAsync(FluxFlattenIterable.java:317)
reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:616)
reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onComplete(FluxFlattenIterable.java:258)
reactor.core.publisher.FluxBuffer$BufferExactSubscriber.onComplete(FluxBuffer.java:179)
reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onComplete(FluxConcatArray.java:183)
reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:79)
reactor.core.publisher.FluxBuffer.subscribe(FluxBuffer.java:72)
reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:104)
reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:183)
reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:173)
reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76)
reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:235)
reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
reactor.ipc.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:207)
reactor.ipc.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:322)
reactor.ipc.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:316)
reactor.ipc.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:581)
reactor.ipc.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:125)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
reactor.ipc.netty.http.HttpOperations.lambda$static$3(HttpOperations.java:261)
reactor.ipc.netty.ReactorNetty$ExtractorHandler.channelRead(ReactorNetty.java:328)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1240)
io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1041)
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
Error has been observed by the following operator(s):
|_ Mono.checkpoint(ReactorServiceBindingsV2.java:52)
|_ Mono.checkpoint(DefaultServices.java:133)
Note: I'm currently using the Staging version to work around #58.
Here's my manifest:
applications:
- name: my-app
routes:
- route: my-hostname.my.domain/my/path
where the hostname is my-hostname
, the configured domain is my.domain
and the context path is /my/path
.
After BGD, this is the output of cf app my-app
:
name: my-app
routes: my-app-new.my.domain, my-app-new.my.domain/my/path, my-hostname.my.domain
Instead of the expected single route, I see 3 different ones (all of them incorrect).
my-hostname.my.domain/my/path
is not mapped at all.my-hostname.my.domain
is mapped. This may break other apps which map to the generic route.my-app-new
route is now blocked by this app. If we were to run BGD for the same app in a different space (with the same domain), it would fail with a "route already in use" error.We are seeing behaviour that looks like the argument to -f
is not being used.
When we create a manifest.yml file, place it in the current directory, and run cf blue-green-deploy myapp
, the output clearly states:
Using manifest file /path/to/manifest.yml
However, running the command from some other directory with -f /path/to/manifest.yml
added to the command arguments causes that same statement not to be output & our deployment fails.
We were not sure whether the -f
argument is still supported because it does not appear in the help
statement for blue-green-deploy, although it is present in the plugin README.md.
In v1.3.0 (this works on v1.1.0, but not on v.1.3.0 after I updated).
Could not map route - Domain my-app-route.my-domain.io not found
The plugin appears to be unable to map the "live" route to the -new
app, giving the error above. When I look at the routes for this space, I definitely see it in the list.
It should also be noted that (because IT bureaucracy) my app names contain underscores and my routes contain dashes (eg: my_app -> my-app.my-domain.io). When bgd
is creating the route for the -new
app, it creates the route as my_app-new.my-domain.io
. That's not a technically valid hostname, but cloud foundry (at least the version used on predix) doesn't seem to have a problem with it.
I'm trying to use the blue-green-deploy plugin, but keep getting the error "Failed to get default shared domain". I enabled CF_TRACE=true to see the request/response, and the response looks OK to my untrained eye.
REQUEST: [2016-07-10T02:55:48Z]
GET /v2/shared_domains HTTP/1.1
Host: api.stage1.ng.bluemix.net
Accept: application/json
Authorization: [PRIVATE DATA HIDDEN]
Content-Type: application/json
User-Agent: go-cli 6.20.0+25b1961 / linux
RESPONSE: [2016-07-10T02:55:49Z]
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Connection: Keep-Alive
Content-Type: application/json;charset=utf-8
Date: Sun, 10 Jul 2016 02:55:49 GMT
Server: nginx
X-Backside-Transport: OK OK
X-Content-Type-Options: nosniff
X-Global-Transaction-Id: 417843439
1e5
{
"total_results": 1,
"total_pages": 1,
"prev_url": null,
"next_url": null,
"resources": [
{
"metadata": {
"guid": "80f7b34d-0c35-47d5-b14a-c0974a9d9b8c",
"url": "/v2/shared_domains/80f7b34d-0c35-47d5-b14a-c0974a9d9b8c",
"created_at": "2014-05-21T14:53:48Z",
"updated_at": null
},
"entity": {
"name": "stage1.mybluemix.net",
"router_group_guid": null,
"router_group_type": null
}
}
]
}
0
Failed to get default shared domain
//=======================================================
I see the implementation of 'DefaultCfDomain' in main.go, and it seems to me that it should be able to find 'stage1.mybluemix.net' when using statement 'response.Resources[0].Entity.Name'. Can anyone help? I definitely think propagating more of the error back to the user than just saying the DefaultCfDomain can't be found would be helpful.
func (p *CfPlugin) DefaultCfDomain() (domain string, err error) {
var res []string
if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", "/v2/shared_domains"); err != nil {
return
}
response := struct {
Resources []struct {
Entity struct {
Name string
}
}
}{}
if err = json.Unmarshal([]byte(res[0]), &response); err != nil {
return
}
domain = response.Resources[0].Entity.Name
return
}
This plugin is exactly what I've been looking for, but I'm deploying a Java application that's packaged into an executable jar. Specifying the path in a manifest file isn't simple, because the manifest expects a literal filename and can't glob or substitute placeholders, and bgd
doesn't support the -p
to specify what to push. With a regular cf push
, I can cf p app -p target/app-*.jar
.
e.g.
cf bgd -f manifest.yml
errors but cf push -f manifest.yml
does not.
Workaround : supply app name as well as manifest.yml.
This would break further if the manifest.yml contained multiple apps.
The current implementation is based on creating and deleting apps after each deployment, but PCF Metrics only display logs of existing apps - meaning I can only see the logs on my current deployed app and the last one. All other logs are not displayed.
I'm trying to Blue-Green deploy a CF application but my smoke tests always fail because the cf-blue-green-deploy plugin maps a testing route with domain mybluemix.net
instead of the domain defined in my manifest (ng.bluemix.net
).
I see that the exising cf-blue-green-deploy code parses the manifest for the domain, but uses the domain provided by DefaultCfDomain()
even if a domain is defined in the manifest.
Hello,
When I try to specify a custom manifest file, the plugin don't used it, but the default manifest.yml.
cf blue-green-deploy batch -f manifest-batch.yml
Result:
Using manifest file /var/jenkins_home/workspace/project_develop/manifest.yml
Hello,
A while ago, I noticed that PCF does not remove the route itself, when app is removed. I discovered it, when I ran cf delete-orphaned-routes -f
in a space, that was used by Jenkins for some time - there were a lot of old, unused routes, all with "-new" suffix.
Maybe it's a good idea to implement that into the code, to completely clean up after itself? The command is simply cf delete-route [routeName]-new -f
.
I just attempted to install this plugin on Windows, and I received a message saying "Plugin requested has no binary available for your OS: windows, amd64".
Given that this plugin is written in Go, that's rather surprising to me. Is there a reason for the lack of a Windows version?
There's an erroneous (and rather confusing) error about reading the manifest followed by a successful read of the manifest! :-)
$ cf blue-green-deploy gordon-test-dev -f gordon-manifest.yml
Error finding manifest: stat manifest.yaml: no such file or directory
Using manifest file gordon-manifest.yml`
Creating app gordon-test-dev-new in org XXXXX / space XXX as XXXX...
OK
I am trying to perform go get after forking the repository to fix #3 and am getting below errors due to change in cloudfoundry/cli project
package github.com/cloudfoundry/cli/cf/configuration/config_helpers: cannot find package "github.com/cloudfoundry/cli/cf/configuration/config_helpers" in any of:
$GOROOT
$GOPATH
package github.com/cloudfoundry/cli/cf/configuration/core_config: cannot find package "github.com/cloudfoundry/cli/cf/configuration/core_config" in any of:
$GOROOT
$GOPATH
package github.com/cloudfoundry/cli/plugin/fakes: cannot find package "github.com/cloudfoundry/cli/plugin/fakes" in any of:
$GOROOT
$GOPATH
the above erring dependencies should look like below now
"github.com/cloudfoundry/cli/cf/configuration/confighelpers"
"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
"github.com/cloudfoundry/cli/plugin/pluginfakes"
There will be fixes to getSpaceGuid function accordingly.
I have done these fixes in my fork but now found internationalization is also broken in main.go
We pass the manifest passed to -f to the push command, but we don't use it when we figure out the routes. The capability is there in the ManifestAppFinder type, but main.go never passes through a manifest path when initialising it.
some time real-time application scenario after release if we need to rollback to previous running instance e.g. "app-name-old". currently we need to all this steps manually. it will be great helpful to provide rollback from "app-name" to makr as "app-name-failed" and "app-name-old" to "app-name".
As per the pull request #12, this project does not build on Go 1.6+. Instead, it gets the following error:
./main.go:173: cannot assign "github.com/nicksnyder/go-i18n/i18n".TranslateFunc to "github.com/cloudfoundry/cli/cf/i18n".T (type "github.com/cloudfoundry/cli/vendor/github.com/nicksnyder/go-i18n/i18n".TranslateFunc) in multiple assignment
This is caused by the lines:
// T needs to point to a translate func, otherwise cf internals blow up
i18n.T, _ = go_i18n.Tfunc("")
And is due to a change about how Go handles vendored dependencies in Go 1.6+. This is present in Go 1.5, but is off by default. It is on by default in Go 1.6, but can be turned off by setting GO15VENDOREXPERIMENT
to 0
. It will be on by default in Go 1.7, and will not be able to be turned off.
The suggested fix for the issue is:
main.go:170
- // T needs to point to a translate func, otherwise cf internals blow up
- i18n.T, _ = go_i18n.Tfunc("")
manifest_test.go:15
+type localeGetter struct{}
+
+func (l localeGetter) Locale() string {
+ return "en-us"
+}
+
var _ = Describe("Manifest reader", func() {
// testing code that calls into cf cli requires T to point to a translate func
- i18n.T, _ = go_i18n.Tfunc("")
+ i18n.T = i18n.Init(localeGetter{})
I've been playing around with bgd on a dev instance of CF, and I noticed that after the process finishes, both applications have the same number of instances. For example, I have an app called "test", and I scale it to 10 instances, and then I use bgd and it is successful, I don't think there's any reason why "test-old" needs to still have 10 instances after the process completes. Same would apply in the failure case, if the smoke tests fail there's no reason why "test-failed" needs to have 10 instances.
I would be happy to take a stab at writing a PR for this, but I'd like to verify that what I'm proposing makes sense. Thanks!
When downloading version 1.2.0 for OSX and installing it says:
Installing plugin blue-green-deploy.osx...
OK
Plugin blue-green-deploy v1.1.0 successfully installed.
This presumably is a publishing error looking at your scripting.
Hi,
we have following case:
manifest-base.yml
---
memory: 768M
instances: 1
path: ../target/pipeline-test.war
domain: domain.com
---
manifest-sbx.yml
---
inherit: manifest-base.yml
applications:
- name: pipeline-test
host: pipeline-test-sbx
When executing blue-green-deploy
command the output looks as follows:
Using manifest file manifests/manifest-sbx.yml
Creating app pipeline-test-new in org *** / space sandbox as ****...
OKCreating route pipeline-test-new.domain.com...
OKBinding pipeline-test-new.domain.com to pipeline-test-new...
OK
Route creation seems to take the value of the parameter name
and does not honor host
.
Parameter host
should take precedence if available. I guess this is a bug.
Best regards,
Oliver
We found an issue using the blue-green-deploy plugin. We think this arises from here: https://github.com/bluemixgaragelondon/cf-blue-green-deploy/blob/master/manifest.go#L22
Given an app manifest with an app name and domains:
---
applications:
- name: test-app
domains:
- testing.com
When the app is deployed using the blue-green-deploy plugin
And the deployment is successful
Then the app has no routes
Is there a reason that host
is required in manifest.yml
? Would you accept a pull request to resolve this issue?
When performing a blue-green deployment (update) on an app which has been scaled to multiple instances, the upgraded app is scaled to one while the old app remains scaled to its original number of instances.
Before blue-green-deploy:
name requested state instances memory disk urls
static-app started 5/5 64M 1G static-app-macrodont-custos.cfapps.io
After blue-green-deploy:
name requested state instances memory disk urls
static-app started 1/1 64M 1G static-app-macrodont-custos.cfapps.io
static-app-old started 5/5 64M 1G
Expected: static-app instances 5/5, static-app-old instances 1/1
My CF has 2 shared domains. Seems like the plugin is not detecting the domain specified in manifest.yml and creates "new" and "old" routes on the default one.
The final app is however on the domain specified in manifest.
Currently, there is no possibility to explicitly specify a manifest when doing a blue-green deploy. I would like to be able to do something like the following:
cf bgd manifest-uat.yml app-name --smok-tests ./smoke_tests.sh
This can be worked around by putting the manifest files in separate directories, but that doesn't feel like a great solution, and makes working with them more awkward than it needs to be.
When I disable-ssh
for my application and then do a bgd
, ssh access is enabled again.
The README:
--delete-old-apps
flagHowever, the published version does not include support for that flag:
$ cf blue-green-deploy <app_name> --delete-old-apps
flag provided but not defined: -delete-old-apps
Usage of blue-green-deploy:
-f string
-smoke-test string
Hello,
We are not completely sure if this is a problem with the plugin or maybe CF ? We are running the open source CF v275 and we have noticed sometimes our deployment fails with
cf-cli: cf version 6.32.0+0191c33d9.2017-09-26
plugin: 1.2.0 (it reports 1.1.0 but file hash wise, we are running 1.2.0, see #42)
Renaming app myapp-new to myapp in org myorg / space live as [email protected]...
Could not rename app - Server error, status code: 400, error code: 100002, message: The app name is taken: myapp
Looking at the log, there is no step where it renames the current myapp
as myapp-old
.
Retrying our deployment job a few times makes it work and as expected, on those deployments the renaming from myapp
as myapp-old
happens as expected.
We haven't found a way to reproduce this, it just randomly happens.
If you need more information, please let me know.
Say we have a domain my.domain
defined in our org. We want to map one of our services to the hostname my.hostname
and context path /my/path
. So the full route becomes https://my-hostname.my.domain/my/path
.
If the app manifest contains a route entry, the plugin tries to resolve the entire value as the domain. For example:
applications:
- name: my-app
routes:
- route: my-hostname.my.domain/my/path
This gives the error:
Could not map route - Domain my-hostname.my.domain not found
Note: The new CF guidelines recommend using only the routes
element - Attribute routes Replaces domain, domains, host, hosts, and no-hostname
In our recent attempt to deploy multiple apps via single manifest using the blue-green-deploy plugin it was noticed that it failed with error :
Could not push new version - Incorrect Usage. Command line flags (except -f) cannot be applied when pushing multiple apps from a manifest file.
Is there a work around for it?
I am trying to use a Continuous Delivery style with a “staging” server for UAT and a “live” server for production.
When deploying to "live", I would like to deploy with “cf copy-app
” to promote the code from “staging” to “live”, rather than "cf push
", which will deploy whatever version of code is present on the invoking machine. This is so that I can be confident that the deployed code is the same as the code that has been through UAT.
To support this, cf-blue-green-deploy
would need a new flag to fetch the app source from an app in a different space using cf copy-app
.
Hi,
It would be great for us if the deployment of the Green app could use 'random-route' if specified in the manifest. The copy of the plugin we are using now always deploys the Green app with a route of <app_name>-new., which has the potential to cause route conflict.
As an aside, the plugin does correctly carry out a blue-green deploy on an existing random route that is attached to the Blue copy of an app.
Thanks
after upgrade bgd to 1.3, it can't map a route to new app. Error message is : Could not map route - Error resolving route:
ENV
cli version : cf version 6.35.0
bgd version : 1.3.0
my cloud foundry has 2 shared domains.
np1.paas.com
np.paas.com
manifest file :
applications:
Environment variable url
from (bluemix) IBM Cloud is suffixed with -new
at the end of the subdomain.
Malformed subdomain is suffixed to a route that should have no subdomain.
Example from manifest below:
a-mybluemix-app-new.a-system-domain.ibm.com
url
environment variable should be the same as if the app were deployed normally with cf push $CF_APP
. -new
and -old
should not be part of the url.
Using cf-blue-green-deploy from staging.
NodeJS app with passport-idaas-openidconnect
and express
dependencies.
Manifest.yml like:
applications:
- name: a-mybluemix-app
buildpack: sdk-for-nodejs
command: node dist/app.js
routes:
- route: a-system-domain.ibm.com
- route: a-mybluemix-app.mybluemix.net
Custom deploy script where existing is renamed and new deploy isn't given an unexpected app name. Routing is taken from manifest.
trap reportError ERR
reportError() {
set +e
if cf app "${CF_APP}_OLD"; then
cf delete $CF_APP -f
cf rename "${CF_APP}_OLD" $CF_APP
fi
exit 1
}
if cf app $CF_APP; then
cf rename $CF_APP "${CF_APP}_OLD"
fi
cf push $CF_APP
cf delete -f "${CF_APP}_OLD"
We store some sensitive data (passwords, access tokents) as environment variables. Since those data is sensitive, we don't have it in the manifest file but on the application instance directly.
It would be great if you can provide a flag that copies all user-provided variables to the new instance.
See commit ae01d5a (disabled test) to reproduce.
BGD Plugin blue green flow when app has manifest when manifest uses hosts and domains [It] maps manifest routes
/home/pipeline/be79174d-cd79-4dbd-9beb-e241fddffc4a/go/src/github.com/bluemixgaragelondon/cf-blue-green-deploy/main_test.go:192
Expected
<[]plugin_models.GetApp_RouteSummary | len:1, cap:1>: [
{
Guid: "",
Host: "app-name-new",
Domain: {Guid: "", Name: "specific.net"},
Path: "",
Port: 0,
},
]
to consist of
<[]interface {} | len:1, cap:1>: [
{
Guid: "",
Host: "app-name-new",
Domain: {Guid: "", Name: "specific.com"},
Path: "",
Port: 0,
},
]
This failure seems to happen about 1 in 10 builds. The root cause seems to be some randomness in whether the first or second domain listed in the manifest is used. There are also occasional acceptance test failures with a similar symptom.
It would be nicer if the binary would supply a list of expected arguments when the program is run without arguments e.g. ./cf-blue-green-deploy
.
We have a basic auth protection for our app. Unfortunately that leads to a 401 http code which is treated as an error. Could you change the check so that it does not fail the code?
state since cpu memory disk details
#0 running 2016-07-26 07:09:10 PM 0.0% 79.5M of 256M 110.7M of 1G
+ curl --fail -I https://xyz-B.eu-gb.mybluemix.net
curl: (22) The requested URL returned error: 401 Unauthorised
++ on_fail
++ finally
++ rm /var/folders/gb/xyz_manifest.XXXXXXXXXX.eZF3dqmA
++ echo 'DEPLOY FAILED - you may need to check '\''cf apps'\'' and '\''cf routes'\'' and do manual cleanup'
DEPLOY FAILED - you may need to check 'cf apps' and 'cf routes' and do manual cleanup
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.