Cloud Foundry Task - Call REST API from the service instance - rest

Is there a way to call a REST API of the service instance running in Cloud Foundry from the Cloud Foundry Task (command).
For instance, I have a Spring Boot app instance called my-rest-app running in PCF. It has an endpoint /sayHello. Using cf run-task my-test-app curl /sayHello?

You can do this but you'd need to tell the task how to locate the given service.
Your task runs in a separate container from the application, so you can't use http://localhost:$PORT because they are separate. That means you need to obtain the URL to your application for the task. You can do that in a couple of different ways.
When Accessing a Different App
To access a different app (i.e. app1's task -> app 2), you need to pass in the URL for the target app. That can be done through an environment variable or a bound service.
The task and service share the same environment variables and bound services, so just set an env variable on your app or bind a service to your app and you'll have access to that through the task.
For example:
cf set-env my-cool-app URL 'http://www.example.com/'
cf restart my-cool-app
cf run-task my-cool-app 'curl "$URL"'
Make sure to properly quote the last command so that $URL is not evaluated locally.
or
cf cups my-service -p url # populate the url when prompted
cf bind-service my-cool-app my-service
cf restart my-cool-app
cf run-task my-cool-app 'curl $(echo "$VCAP_SERVICES" | jq -r ".[\"user-provided\"][0].credentials.url")'
This is a little more complicated but pulls the URL to request out of the VCAP_SERVICES env variable which is where the bound service information lives.
When Accessing the Same App
If you are trying to access the same app (i.e. app1's task -> app1), you can pull the URL from VCAP_APPLICATION so you don't need an env variable or bound service.
For example:
cf run-task my-cool-app 'curl https://$(echo "$VCAP_APPLICATION" | jq -r ".uris[0]")'
This will pull the first URI that's mapped to the app. If you have multiple routes bound to your app, you may need to adjust this to pick a different URI. This should include a route path if your route has a path associated with it.
If you need to access /actuator/health or a specific subpath under the app, you can just append that onto the end of the URI fetched here.

Related

injected db credentials change when I deploy new app version to cloud

I deploy a web app to a local cloudfoundry environment. As a database service for my DEV environment I have chosen a Marketplace service google-cloudsql-postgres with the plan postgres-db-f1-micro. Using the Web UI I created an instance with the name myapp-test-database and mentioned it in the CF Manifest:
applications:
- name: myapp-test
services:
- myapp-test-database
At first, all is fine. I can even redeploy the existing artifact. However, when I build a new version of my app and push it to CF, the injected credentials are updated and the app can no longer access the tables:
PSQLException: ERROR: permission denied for table
The tables are still there, but they're owned by the previous user. They were automatically created by the ORM in the public schema.
While the -OLD application still exists I can retrieve the old username/password from the CF Web UI or $VCAP_SERVICES and drop the tables.
Is this all because of Rolling App Deployments? But then there should be a lot of complaints.
If you are strictly doing a cf push (or restart/restage), the broker isn't involved (Cloud Controller doesn't talk to it), and service credentials won't change.
The only action through cf commands that can modify your credentials is doing an unbind followed by a bind. Many, but not all, service brokers will throw away credentials on unbind and provide new, unique credentials for a bind. This is often desirable so that you can rotate credentials if credentials are compromised.
Where this can be a problem is if you have custom scripts or cf cli plugins to implement rolling deployments. Most tools like this will use two separate application instances, which means you'll have two separate bindings and two separate sets of credentials.
If you must have one set of credentials you can use a service key to work around this. Service keys are like bindings but not associated with an application in CloudFoundry.
The downside of the service key is that it's not automatically exposed to your application, like a binding, through $VCAP_SERVICES. To workaround this, you can pass the service key creds into a user-provided service and then bind that to your application, or you can pass them into your application through other environment variables, like DB_URL.
The other option is to switch away from using scripts and cf cli plugins for blue/green deployment and to use the support that is now built into Cloud Foundry. With cf cli version 7+, cf push has a --strategy option which can be set to rolling to perform a rolling deployment. This does not create multiple application instances and so there would only ever exist one service binding and one set of credentials.
Request a static username using the extra bind parameter "username":
cf bind-service my-app-test-CANDIDATE myapp-test-database -c "{\"username\":\"myuser\"}"
With cf7+ it's possible to add parameters to the manifest:
applications:
- name: myapp-test
services:
- name: myapp-test-database
parameters: { "username": "myuser" }
https://docs.cloudfoundry.org/devguide/services/application-binding.html#arbitrary-params-binding
Note: Arbitrary parameters are not supported in app manifests in cf CLI v6.x. Arbitrary parameters are supported in app manifests in cf CLI v7.0 and later.
However, I can't find the new syntax here: https://docs.cloudfoundry.org/devguide/deploy-apps/manifest-attributes.html#services-block . The syntax I use comes from some other SO question.

How to get multi container application's URL from Docker Compose Task in Azure Pipeline?

I've configured multi container using Docker Compose Task in Azure Pipeline. I could not able to get URL for the multi container application.
Do I need to configure the app service along with the docker compose task?
Please guide!!!
UPDATE
In order to get the application's URL from DockerCompose Task, Can make use of Azure CLI commands provided in the following documentation link suggested by Merlin Liang - MSFT
https://learn.microsoft.com/en-us/azure/container-instances/container-instances-multi-container-yaml#view-deployment-state
Not sure here which URL is you are looking for.
1) If what you means is the browsing URL of your APP, you could find it in Overview tab of app service:
Even though it is a multi-container app, this URL has fixed format, and do not be affected by anything:
http://<your-app-name>.azurewebsites.net
2) If what you want is a integrate URL which used to notify/update the app service once a new version of the image is available.
Just go Container settings => Continuous Deployment => Webhook URL:
Do I need to configure the app service along with the docker compose
task?
This depend on your actual demand. It is not necessary in most scenarios.
Docker compose task used to orchestration your container. Based on your last SO ticket, you just run service. In fact, in Azure Web App for Containers task. it integrate this part:
If you think here it can not satisfied your usage, you could make use of Docker compose task.
Updated in 2020/3/2:
If someone just build and push the containerization app into ACR, without any integrate with Azure app service. At this time, the browsing url should be look like localhost:<port>.
To get exact host name and ip address, just run below commands to get:
az container show --resource-group myResourceGroup --name myContainerGroup --output table

What's the hostname of openshift master server for internal access?

If I want to access the REST API of the openshift master server from anywhere in my company I use https://master.test04.otc-test.company.com:8443 which works just fine.
Now I'm writing an admin application that is accessing the REST API and is deployed in this openshift cluster. Is there a generic name or environment variable in openshift to get the hostname of the master server?
Background: My admin application will be deployed on multiple openshift clusters which do not have the same URL. It would be very handy to have them autodiscover the hostname of the current master server instead of configuring this value for every deployment.
Use environment variables:
https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
In the container, unless service account details are not being mounted, you can also access the directory:
/var/run/secrets/kubernetes.io/serviceaccount
In this you can then find a token file which contains the access token for the service account the container runs as. This means you can create a separate service account for the application in that project, and use RBAC to control what it can do via the REST API.
That same directory also has a namespace file so you know what project the container is running in, and files with certificates to use when accessing the REST API over a secure connection.
This is the recommended approach, rather than trying to pass an access token to your application through its configuration.
Note that in OpenShift 4, if you need to access the OAuth server endpoint, it is on a separate URL to what the REST API is. In 3.X, they were on the same URL.
In 4.0, you can access the path /.well-known/oauth-authorization-server on the REST API URL, to get information about the separate OAuth server endpoint.
For additional information on giving REST API access to an application via a service account, see:
https://cookbook.openshift.org/users-and-role-based-access-control/how-do-i-enable-rest-api-access-for-an-application.html
Note that that page currently says you can use https://openshift.default.svc.cluster.local as URL, but this doesn't work in OpenShift 4.

Bluemix binding WIoTP service using cf bind-service custom configuration

Cloud foundry provides facility to specify credentials as part of cf bind-service command. I am using this facility to specify custom credentials while binding WIoTP service to an app in Bluemix. As in below anonymized command
cf bind-service demo-app dev-iotf-service -c '{"apiKey":"a-dummyorg-dummy12345","apiToken":"dummyapikey","base_uri":"https://dummyorg.internetofthings.ibmcloud.com:443/api/v0001","http_host":"dummyorg.internetofthings.ibmcloud.com","iotCredentialsIdentifier":"dummyid","mqtt_host":"dummyorg.messaging.internetofthings.ibmcloud.com","mqtt_s_port":8883,"mqtt_u_port":1883,"org":"dummyorg"}'
I have generated service-key using cf create-service-key command.
Invalid configuration provided for -c flag. Please provide a valid
JSON object or path to a file containing a valid JSON object.
What am I doing wrong? Or is it that Bluemix,WIoTP currently doesn't support specifying custom credentials as part of cf bind-service command. I really don't want to go CUPs route as that would need change in quite a few apps which expect WIoTP credentials to be present in iotf-service object.
I can invoke the command exactly as you have specified (apart from substituting my app and service name) using bx client:
bx cf bind-service myapp my-iotf-service -c '{"apiKey":"a-dummyorg-dummy12345","apiToken":"dummyapikey","base_uri":"https://dummyorg.internetofthings.ibmcloud.com:443/api/v0001","http_host":"dummyorg.internetofthings.ibmcloud.com","iotCredentialsIdentifier":"dummyid","mqtt_host":"dummyorg.messaging.internetofthings.ibmcloud.com","mqtt_s_port":8883,"mqtt_u_port":1883,"org":"dummyorg"}'
and it works. Possibly you simply have an old cf client. You should use the bx client as available at https://console.bluemix.net/docs/cli/index.html#downloads
However, IoTP does not support this and so ignores anything sent via this means. The obvious case would be to either create a limited API key or use an API key you have already created as you are attempting. Unfortunately you would need to submit an idea at https://ibmcloud.ideas.aha.io/?category=6343565373323972470 to get it considered.

How do I share the URL of my application with another application in Bluemix?

I have two applications on Bluemix and I need to give the URL of one application to the other one.
$response = http_get("myOrdersApp12345.mybluemix.net/api");
Hard coding the URL in my source code seems like a bad idea... What if the url changes?
Hard coding the URL or any credentials in the source is bad practice. In Bluemix, you can pass these credentials to your application using the VCAP_SERVICES environment variable. This is same environment variable that holds credentials for Bluemix services.
You are essentially creating your own service visible to your org and space by creating a user-provided service.
Create a new service that provides the url to consumers of this service:
$ cf cups myOrdersAppService -p "url"
url> myOrdersApp12345.mybluemix.net/api
Creating user provided service myOrdersApp in org **** / space ****
OK
And then binding this service to the application that wants this “url” information
$ cf bind-service myOtherApplication myOrdersAppService
myOtherApplication can how get the url by parsing the VCAP_SERVICES environment variable. For example, in PHP:
$services = getenv("VCAP_SERVICES");
$services_json = json_decode($services, true);
for ($i = 0; $i < sizeof($services_json["user-provided"]); $i++){
if ($services_json["user-provided"][$i]["name"] == "myOrdersApp"){
$ordersHost = $services_json["user-provided"][$i]["credentials"]["url"];
$response = http_get($ordersHost);
}
}
You can use this same method to share credentials of any external services (like databases). When using the microservice architecture, this feature becomes extremely useful.
$ cf cups myExternalDB -p "host, username, password"
host> 123.123.123.123
username> myusername
password> mypassw0rd
For more details, check out this doc: http://docs.cloudfoundry.org/devguide/services/user-provided.html
I agree with Ram's suggestion to retrieve service parameters via VCAP_SERVICES, especially when it specifies information intrinsic to the binding of a service to your application like credentials. However, for more mundane configuration properties (e.g., what languages are supported and where are the translations located? What URL should be used for invoking this REST service?), traditional methods like passing them on the command line, retrieving them from a configuration file, or getting them from environment variables specified by the admin at deployment time are perfectly legitimate.
Pat Mueller's Keeping secrets – how your cloud application should access credentials and other private data nicely summarizes the options and tradeoffs. Most importantly, he underscores the importance of not hardcoding sensitive information, especially given the likelihood that code will be stored in a repository where it's not readily evident who will have access, unlike a deployment script maintained by the system admin.