External websocket access from a 3rd party application

This is RancherDave asking a questions on behalf of one of our beta customers. They would like their application to have a persistent websocket connection to Rancher so that their application could continually be updated instead of having to constantly poll via the API. For example, their application informs end users when an environment and containers are available for consumption and a websocket connection would be able to do this instantaneously.

This is how the UI works, others can use it too. Example: https://gist.github.com/vincent99/491afed2306ba448dd89

1 Like

Is embedding the access key and access secret in the URI still a valid way of authenticating a third party application against the websocket api?

I just tried this with a few different api keys and it always fails with “invalid_status_code”
“ws://#{access_key}:#{secret_key}@localhost:5000/v1/subscribe?eventNames=resource.change”

There’s nothing Rancher-specific about the proto://user:pass@host/path syntax, it’s just a standard URI that browsers/node.js libraries accept. The user and pass part gets turned into a header for HTTP Basic auth.

Not sure what language you’re using but your client library may not support that syntax and have a different way to set HTTP headers instead. The equivalent is to base64 encode the string username+":"+password and send a Authorization: Basic the_resulting_base64_string header.

Is there a list of event subscriptions somewhere?

The only useful event right now is the resource.change that I mentioned (and pings that you also get every 5 seconds).

I put together a small microservice POC container for dynamic integration between Rancher and Consul, using the websocket events from Rancher. This is no way is production ready, but I think the concept works.

1 Like

I am trying to get the example running, but I am getting the error

Error: unexpected server response (404)                                                                                                        
    at ClientRequest.response (/projects/myapp/node_modules/ws/lib/WebSocket.js:719:10)                                                         
    at ClientRequest.g (events.js:260:16)                                                                                                      
    at emitOne (events.js:77:13)                                                                                                               
    at ClientRequest.emit (events.js:169:7)                                                                                                    
    at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:415:21)                                                              
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)                                                                              
    at TLSSocket.socketOnData (_http_client.js:305:20)                                                                                         
    at emitOne (events.js:77:13)                                                                                                               
    at TLSSocket.emit (events.js:169:7)                                                                                                        
    at readableAddChunk (_stream_readable.js:146:16)                  

something I’m doing wrong ? I used npm install ws

There’s no input validation in the example, so make sure you’re passing the address, access key, secret key and a project id. You can add console.log('URL:',url); below where the url is constructed to check what it produced.

I was trying

var url = 'https://'+accessKey+':'+secretKey+'@'+host+'/v1/subscribe?eventNames=resource.change';

as I wanted to subscribe to all activity in app projects - is that no possible ?

No; you can connect to them all individually but subscription is only per-project.

ok, forgive this old man - what is a “project” ? Is it a stack ? (I know the api and the UI use different terms)

Hoping that a project is not a stack, otherwise I have to create a websocket connection for every stack which seems, well, silly …

API project = UI Environment
API environment = UI Stack

We’ll fix this in API v2 someday…

phew - thanks for the help . I’ll go and try get environments^h^h^h^h^h^h^h^h^h^hprojects monitoring working :wink:

is there any documentation on the websocket api ? Events, commands etc ?

What is shown in that gist is pretty much all the subscribe websocket does. You get a frame with a change event, which has a field called data that contains an updated copy of the changed resource.

I’ve been logging all the results of the changes. However, I can’t seem to find anything “simple” that tells me that an environment / project has been created, stopped or started.

For example, when shutting down a simple environment (1 container) I get this [snipped out all the nulls for space]

ENV { id: 'c706deaa-cc4c-4abc-9f81-19f36eb143df',                                                                                             
  name: 'resource.change',                                                                                                                    
  resourceId: '1e213',                                                                                                                        
  resourceType: 'environment',                                                                                                                
  data:                                                                                                                                       
   { resource:                                                                                                                                
      { id: '1e213',                                                                                                                          
        type: 'environment',                                                                                                                  
        links: [Object],                                                                                                                      
        actions: [Object],                                                                                                                    
        name: 'ubuntu',                                                                                                                       
        state: 'active',                                                                                                                      
        accountId: '1a9',                                                                                                                     
        created: '2016-06-14T09:26:54Z',                                                                                                      
        createdTS: 1465896414000,                                                                                                             
        externalId: '',                                                                                                                       
        healthState: 'unhealthy',                                                                                                             
        kind: 'environment',                                                                                                                  
        startOnCreate: true,                                                                                                                  
        transitioning: 'no',                                                                                                                  
        uuid: '3e0e1e4c-bb25-40f1-a3f9-154aa1dc131d' } },                                                                                     
  time: 1465980136651,                                                                                                                        

}

with the exception of healthState: ‘unhealthy’, I can’t see much in there to tell me why this environment triggered the change event on the socket.

Likewise, when I startup I get 2 events

ENV { id: 'c5638893-6a1c-4beb-a932-09aa4b4154b7',                                                                                             
  name: 'resource.change',                                                                                                                    
  resourceId: '1e213',                                                                                                                        
  resourceType: 'environment',                                                                                                                
  data:                                                                                                                                       
   { resource:                                                                                                                                
      { id: '1e213',                                                                                                                          
        type: 'environment',                                                                                                                  
        links: [Object],                                                                                                                      
        actions: [Object],                                                                                                                    
        name: 'ubuntu',                                                                                                                       
        state: 'active',                                                                                                                      
        accountId: '1a9',                                                                                                                     
        created: '2016-06-14T09:26:54Z',                                                                                                      
        createdTS: 1465896414000,                                                                                                             
        externalId: '',                                                                                                                       
        healthState: 'unhealthy',                                                                                                             
        kind: 'environment',                                                                                                                  
        startOnCreate: true,                                                                                                                  
        transitioning: 'no',                                                                                                                  
        uuid: '3e0e1e4c-bb25-40f1-a3f9-154aa1dc131d' } },                                                                                     
  time: 1465980348700,                                                                                                                        
 }              

and

ENV { id: 'eb47b739-ea4a-4e0d-8da8-105e6b48181b',                                                                                             
  name: 'resource.change',                                                                                                                    
  resourceId: '1e213',                                                                                                                        
  resourceType: 'environment',                                                                                                                
  data:                                                                                                                                       
   { resource:                                                                                                                                
      { id: '1e213',                                                                                                                          
        type: 'environment',                                                                                                                  
        links: [Object],                                                                                                                      
        actions: [Object],                                                                                                                    
        name: 'ubuntu',                                                                                                                       
        state: 'active',                                                                                                                      
        accountId: '1a9',                                                                                                                     
        created: '2016-06-14T09:26:54Z',                                                                                                      
        createdTS: 1465896414000,                                                                                                             
        externalId: '',                                                                                                                       
        healthState: 'healthy',                                                                                                               
        kind: 'environment',                                                                                                                  
        startOnCreate: true,                                                                                                                  
        transitioning: 'no',                                                                                                                  
        uuid: '3e0e1e4c-bb25-40f1-a3f9-154aa1dc131d' } },                                                                                     
  time: 1465980352703,                                                                                                                        
}                  

I don’t understand the purpose of the first event (it’s the same as the last event when shutting down) and the second event only tells me that the env is healthy

So, I can “guess” that when an environment has started, it gets the “healthy” event - but this can be the case if one of the services is down for a while and then brought back up

I suppose I’m looking for simple ENV events, much like the container events start, kill, die and stop

There is no concept of a “stopped” or “started” Stack (environment), they do not have an inactive state. When you say “Stop Services” we just stop the individual services within it. While they’re stopping they are temporarily unhealthy, which bubbles up to the stack and triggers a change event.

The purpose of this websocket is to allow the UI to keep an up-to-date copy of each resource in memory so that the screen is always up to date. So a change is sent whenever the record is changed with a new copy of the resource, but it doesn’t tell you what about the resource has changed or why it was sent.

To determine if an stack/environment is “new”, you would need to have a list of all of the known ones and see if the change event is for one you don’t know about. Or look at the created date if approximate is close enough. Or watch for events for auditLog resources with eventType: "api.stack.create".

What needs to be done to connect to websocket from external application? Can you give me a hint.

@CrystalMethod the link farther up in this thread ( https://gist.github.com/vincent99/491afed2306ba448dd89 ) is actual code that connects to it.