Package: cloudfoundry-client
The cf-python-client repo contains a Python client library for Cloud Foundry.InstallingSupported versionsStarting version1.11.0, versions older than python3.6.0will not be supported anymore. This late version was released by the end 2016.
For those that are still using python 2.7, it won’t be supported by the end of 2020 and all library shall stop supporting it.Starting version1.25.0, versions older than python3.7.0will not be supported anymore.Starting version1.36.0, versions older than python3.8.0will not be supported anymore.Seeofficial documentation.From pip$pipinstallcloudfoundry-clientFrom sourcesTo build the library run :$pythonsetup.pyinstallRun the clientTo run the client, enter the following command :$cloudfoundry-clientThis will explains you how the client works. At first execution, it will ask you information about the platform you want to reach (url, login and so on).
Please note that your credentials won’t be saved on your disk: only tokens will be kept for further use.Use the client in your codeYou may build the client and use it in your codeClientTo instantiate the client, nothing easierfromcloudfoundry_client.clientimportCloudFoundryClienttarget_endpoint='https://somewhere.org'proxy=dict(http=os.environ.get('HTTP_PROXY',''),https=os.environ.get('HTTPS_PROXY',''))client=CloudFoundryClient(target_endpoint,proxy=proxy,verify=False)# init with user credentialsclient.init_with_user_credentials('login','password')# init with refresh token (that will retrieve a fresh access token)client.init_with_token('refresh-token')# init with access and refresh token (if the above method is not convenient)client.refresh_token='refresh-token'client._access_token='access-token'You can also instantiate the client by reading the config file generated bycf login, which allows for authenticating via SSO and LDAP:# init with endpoint & token from the cf cli config filefromcloudfoundry_client.clientimportCloudFoundryClient# use the default file, i.e. ~/.cf/config.jsonclient=CloudFoundryClient.build_from_cf_config()# or specify an alternative path# - other kwargs can be passed through to CloudFoundryClient instantiationclient=CloudFoundryClient.build_from_cf_config(config_path="some/path/config.json",proxy=proxy,verify=False)It can also be instantiated with oauth code flow if you possess a dedicated oauth application with its redirectionfromflaskimportrequestfromcloudfoundry_client.clientimportCloudFoundryClienttarget_endpoint='https://somewhere.org'proxy=dict(http=os.environ.get('HTTP_PROXY',''),https=os.environ.get('HTTPS_PROXY',''))client=CloudFoundryClient(target_endpoint,proxy=proxy,verify=False,client_id='my-client-id',client_secret='my-client-secret')@app.route('/login')deflogin():globalclientreturnredirect(client.generate_authorize_url('http://localhost:9999/code','666'))@app.route('/code')defcode():globalclientclient.init_authorize_code_process('http://localhost:9999/code',request.args.get('code'))And then you can use it as follows:fororganizationinclient.v2.organizations:print(organization['metadata']['guid'])API V2EntitiesEntities returned by api V2 calls (organization,space,app..) are navigable ie you can call the method associated with thexxx_urlentity attribute
(note that if the attribute’s name ends with a list, it will be interpreted as a list of object. Other wise you will get a single entity).fororganizationinclient.v2.organizations:forspaceinorganization.spaces():# perform a GET on spaces_url attributeorganization_reloaded=space.organization()# perform a GET on organization_url attributeApplication object provides more methods such asinstancesstatsstartstopsummaryAs instance, you can get all the summaries as follows:Or else:forappinclient.v2.apps:print(app.summary())Available managersSo far the implemented managers that are available are:service_plansservice_plan_visibilitiesservice_instancesservice_keysservice_bindingsservice_brokersappseventsbuildpacksorganizationsspacesservicesroutesshared_domainsprivate_domainssecurity_groupsNote that even if, while navigating, you reach an entity manager that does not exist, the get will be performed and you will get the expected entities.
For example, event entity manager is not yet implemented but you can doforappinclient.v2.apps:foreventinapp.events():handle_event_object()All managers provide the following methods:list(**kwargs): return aniteratoron entities, according to the given filtered parametersget_first(**kwargs): return the first matching entity according to the given parameters. Returns`Noneif none returnedget: perform aGETon the entity. If the entity cannot be find it will raise an exception due to httpNOT FOUNDresponse status__iter__: iteration on the manager itself. Alias for a no-filter list__getitem__: alias for thegetoperation_create: the create operation. Since it is a generic operation (only takes adictobject), this operation is protected_update: the update operation. Since it is a generic operation (only takes a the resource id and adictobject), this operation is protected_remove: the delete operation. This operation is maintained protected.# Assume you have an organization named `test-org` with a guid of `test-org-guid`org_get=client.v2.organizations.get('test-org-guid')org_get_first=client.v2.organizations.get_first(**{'name':'test-org'})org_from_list=list(client.v2.organizations.list(**{'name':'test-org'}))[0]assertorg_get==org_get_first==org_from_list# You can also specify multiple values for a query parameter.fororganizationinclient.v2.organizations.list(**{'name':['org1','org2']}):print(organization['metadata']['guid'])# Order and Paging parameters are also supported.query={'order-by':'name','order-direction':'desc','results-per-page':100}fororganizationinclient.v2.organizations.list(**query):print(organization['entity']['name'])API V3EntitiesEntities returned by API V3 calls transcripts links by providing a call on the object with the name of the link itself.
Let’s explain it with the next codeforappinclient.v3.apps.list(space_guids='space_guid'):fortaskinapp.tasks():print('Task%s'%task['guid'])app.stop()space=app.space()Another example:app=client.v3.apps['app-guid']fortaskinapp.tasks():task.cancel()fortaskinclient.v3.tasks.list(app_guids=['app-guid-1','app-guid-2']):task.cancel()When supported by the API, parent entities can be included in a single call. The included entities replace the links mentioned above.
The following code snippet issues three requests to the API in order to get app, space and organization data:app=client.v3.apps.get("app-guid")print("App name:%s"%app["name"])space=app.space()print("Space name:%s"%space["name"])org=space.organization()print("Org name:%s"%org["name"])By changing the first line only, a single request fetches all the data. The navigation from app to space and space to organization remains unchanged.app=client.v3.apps.get("app-guid",include="space.organization")Available managers on API V3 are:appsbuildpacksdomainsfeature_flagsisolation_segmentsjobsorganizationsorganization_quotasprocessesrolessecurity_groupsservice_brokersservice_credential_bindingsservice_instancesservice_offeringsservice_plansspacestasksThe managers provide the same methods as the V2 managers with the following differences:get(**kwargs): supports keyword arguments that are passed on to the API, e.g. “include”Networkingpolicy serverAt the moment we have only the network policies implementedforpolicyinclient.network.v1.external.policies.list():print('destination protocol ={}'.format(policy['destination']['protocol']))print('destination from port ={}'.format(policy['destination']['ports']['start']))print('destination to port ={}'.format(policy['destination']['ports']['end']))Available managers on API V3 are:policyThis manager provides:list(**kwargs): return aniteratoron entities, according to the given filtered parameters__iter__: iteration on the manager itself. Alias for a no-filter list_create: the create operation. Since it is a generic operation (only takes adictobject), this operation is protected_remove: the delete operation. This operation is maintained protected.Application logsRecent logs of an application can be get as follows:app=client.v2.apps['app-guid']forloginapp.recent_logs():print(log)Logs can also be streamed using a websocket as follows:app=client.v2.apps['app-guid']forloginapp.stream_logs():# read message infinitely (use break to exit... it will close the underlying websocket)print(log)# orforloginclient.doppler.stream_logs('app-guid'):# read message infinitely (use break to exit... it will close the underlying websocket)print(log)Logs can also be streamed directly from RLP Gateway:importasynciofromcloudfoundry_client.clientimportCloudFoundryClienttarget_endpoint='https://somewhere.org'proxy=dict(http=os.environ.get('HTTP_PROXY',''),https=os.environ.get('HTTPS_PROXY',''))rlp_client=CloudFoundryClient(target_endpoint,client_id='client_id',client_secret='client_secret',verify=False)# init with client credentialsrlp_client.init_with_client_credentials()asyncdefget_logs_for_app(rlp_client,app_guid):asyncforloginrlp_client.rlpgateway.stream_logs(app_guid,params={'counter':'','gauge':''},headers={'User-Agent':'cf-python-client'})):print(log)loop=asyncio.get_event_loop()loop.create_task(get_logs_for_app(rlp_client,"app_guid"))loop.run_forever()loop.close()Command Line InterfaceThe client comes with a command line interface. Runcloudfoundry-clientcommand. At first execution, it will ask you information about the target platform and your credential (do not worry they are not saved). After that you may have a help by runningcloudfoundry-client-hOperations (experimental)For now the only operation that is implemented is the push one.fromcloudfoundry_client.operations.push.pushimportPushOperationoperation=PushOperation(client)operation.push(client.v2.spaces.get_first(name='My Space')['metadata']['guid'],path)Issues and contributionsPlease submit issue/pull request.You can run tests by doing so. In the project directory:$exportPYTHONPATH=main$python-munittestdiscovertest# or even$pythonsetup.pytest