Bluemix binding WIoTP service using cf bind-service custom configuration - ibm-cloud

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.

Related

Cloud Foundry Task - Call REST API from the service instance

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.

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 a foundary service whitelist IPs

We have a GUI that manages Cloud Foundry, and there's a link that show an instance with IP white list external dependency (quite large) How can I easily re-create this config as JSON, and recreate to diff Foundry env ?
It's not entirely clear what is being presented in your GUI but it sounds like it might be the application security groups. You might try running cf security-groups or cf security-group <name> to see if this information matches up with what's displayed in the GUI.
If that's what you want, you can use the following API calls to obtain the JSON data & recreate it in another environment.
1.) List all the security groups: http://apidocs.cloudfoundry.org/1.40.0/security_groups/list_all_security_groups.html
2.) List security groups applied to all applications: http://apidocs.cloudfoundry.org/1.40.0/security_group_running_defaults/return_the_security_groups_used_for_running_apps.html
3.) List security groups applied to all staging containers: http://apidocs.cloudfoundry.org/1.40.0/security_group_staging_defaults/return_the_security_groups_used_for_staging.html
4.) Retrieve a particular security group: http://apidocs.cloudfoundry.org/1.40.0/security_groups/retrieve_a_particular_security_group.html
And you can find more details about the API calls here: http://apidocs.cloudfoundry.org/
You can also run the cf cli commands above with the -v flag to show the HTTP requests being made by the CLI to obtain the information that's displayed.
Hope that helps!

How do I manage org and space users in bluemix using cf command line?

Bluemix provides a CF command line for download to manage applications.
We want to use CF (or any other command line tools ) to manage Organization and Space users. This will allow us to programmatically sync the user list.
Specifically I am looking for
cf enroll-user
cf add-user
cf remove-user
cf unenroll-use
the cf command already lists the users for a given ORG and SPACE.
The simple answer is to read the docs. See "Creating and Managing Users with the cf CLI." It documents commands like create-user, set-org-role, and set-space-role.
For example: Use cf create-user USERNAME PASSWORD to create a new user. The problem is, when you try to do this in Bluemix, you get an error:
>cf create-user jdoe password
Creating user jdoe as bwoolf...
FAILED
Error creating user jdoe.
Server error, status code: 403, error code: access_denied, message: Invalid token does not contain resource id (scim)
You get a similar error when you try to run set-org-role or set-space-role:
FAILED
Server error, status code: 403: Access is denied. You do not have privileges to execute this command.
Why did you get this error? Like #RandalAnders explained, Bluemix currently blocks users from using these user administration commands in the CF CLI. For the time being, you'll need to perform these actions using the Bluemix Dashboard.
Currently, it is not possible within Bluemix to use the CF CLI for certain management commands, as they require administrative privileges. We are exploring expanding the scope of the commands used in the CLI and would be interested in hearing any other use cases you may have.
you can not create a user on bluemix using cf cli since it needs admin privileges. To add a user, you will need to use bluemix cli 'bluemix iam account-user-invite' to invite a user to your account with a org/space role assigned. There are other account/org/space/role management commands under 'bluemix iam'.
Download bluemix CLI here: http://clis.ng.bluemix.net

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.