# API There are lots of different APIs available in Rancher, but the primary two are [Norman](https://github.com/rancher/norman) and [Steve](https://github.com/rancher/steve) ## Norman Norman is older and mainly used by the [Ember UI](https://github.com/rancher/ui). It presents an opinionated view of some of the common resources in a Kubernetes cluster, with lots of features to make the client's life easier. Fields are renamed to be named more consistently, deeply-nested structures are flattened out somewhat, complicated multi-step interactions with the k8s API are orchestrated in the server and hidden from you, etc. It attempts to bridge the gap from Rancher 1.x's usability, and is quite nice if it does what you need. But _only_ the types that Norman supports are exposed, and you can _only_ interact with the resources in the namespaces assigned to a Project. Types Norman doesn't know about and namespaces not assigned to a project are effectively invisible. ## Steve Steve is newer, and the primary API used here. It works in the opposite direction, starting with a completely unopinionated view of every resource available in a cluster, and then adding custom logic only where needed. Every type and every namespace are directly addressable. This still adds some critical functionality over directly talking to the k8s API, such as: - It's presented following our [api-spec](https://github.com/rancher/api-spec), so the same client libraries work for any of our APIs, including the in-browser generic [api-ui](https://github.com/rancher/api-ui). - "Watches" to find out when a resource changes are aggregated into a single websocket which keeps track of what's connected and can resume the stream, rather than many independent calls to the native k8s implementation - The "counts" resource internally watches everything to keep track of how many of every type of resource there are in every namespace and state, which allows us to show all the types that are "in use" and how many there are in the left nav. - Schemas and links on each resource efficiently identify what permissions the user making the request has, so that actions in the UI can be hidden or disabled if not allowed for the current user instead of letting them try and having the server reject it. - Normalizing the different and sometimes inconsistent state/status/conditions data from resources into a single logical view of the world the UI can present. - RPC-style actions to do more complicated workflows on the server side when appropriate A key concept in Steve is that although the UI makes imperative calls to the Steve API, Steve is designed to capture all operations in Kubernetes resources. That means the only way to perform any operation with the Steve API is by requesting it to create or manipulate YAML files. This is in contrast to the Norman API, which had a concept of 'actions' - imperative API calls that would perform an operation. For example, while Norman had defined an action to perform encryption key rotation, the only way to achieve the same result in Steve would be to update the provisioning cluster Kubernetes resource. ## Endpoints In a production setup these are all handled natively by Rancher. For development of dashboard, they are proxied to the Rancher install that the `API` environment variable points at. Endpoint | Notes -------------------------|------- `/v3` | Norman API `/v3-public` | Norman unauthenticated API (mostly for info required to login) `/v1` | Steve API for the management ("local") cluster `/k8s/clusters/` | Proxy straight to the native k8s API for the given downstream cluster `/k8s/clusters//v1` | Steve API for given downstream cluster via the server proxy The older Norman API is served on `/v3`. The newer Steve API (see [here](https://github.com/rancher/api-spec/blob/master/specification.md) for spec) is served on `/v1` . In both cases the schemas returned dictate - Which resources are shown - What operations (create, update, delete, etc) can be made against resource/s - What actions (archive, change password, etc) can be made against resource/s In addition the resources themselves can dictate - What actions can be made against the collection The above, plus other factors, will effect what is shown by the UI - Resources in the cluster explorer - Edit resource buttons - Delete resource - etc There are other factors that assist in this, namely values from the `type-map`. More details can be found throughout this document. ## Exploring the API The API serves up an interface to [browse both Norman and Steve APIs](https://github.com/rancher/api-ui). Both will list supported schemas and allow the user to fetch individual or collections of resources. The schemas will describe the actions executable against individual or collections of resource. For Norman it will also show fields that can be filtered on. The dashboard will proxy requests to the API, so the interfaces are available via `/v3` (Norman) and `/v1` (Steve) ## Synching State The high-level way the entire UI works is that API calls are made to load data from the server, and then a "watch" is started to notify us of changes so that information can be kept up to date at all times without polling or refreshing. You can load a single resource by ID, an entire collection of all those resources, or something in between, and they should still stay up to date. This works by having an array of a single authoritative copy of all the "known" models saved in the API stores (`management` & `cluster`) and updating the data when an event is received from the "subscribe" websocket. The update is done on the _existing_ copy, so that anything that refers to it finds out that it changed through Vue's reactivity. When manipulating models or collections of results from the API, some care is needed to make sure you are keeping that single copy and not making extras or turning a "live" array of models into a "dead" clone of it. The most basic operations are `find({type, id})` to load a single resource by ID, `findAll({type})` load all of them. These (anything starting with `find`) are async calls to the API. Getters like `all(type)` and `byId(type, id)` are synchronous and return only info that has already been previously loaded. See `plugins/dashboard-store/` for all the available actions and getters. ## Resources A resource is an instance of a schema e.g. the `admin` user is an instance of type `management.cattle.io.user` from the `Steve` API. ## Schemas Schemas are provided in bulk via the APIs and cached locally in the relevant store (`management`, `rancher`, etc). A schema can be fetched synchronously via store getter ```ts import { POD } from '@shell/config/types'; this.$store.getters['cluster/schemaFor'](POD)` ``` > Troubleshooting: Cannot find new schema > > Ensure that your schema text in `/config/types.js` is singular, not plural As mentioned before a schema dictates the functionality available to that type and what is shown for the type in the UI. ## Types Each type has a Kubernetes API group and a name, but not necessarily a human-readable name. Types are used mainly for building side navigation and defining how the UI should build forms and list views for each resource. For more information about types and how to use them, there are helpful comments in `store/type-map.js`. ### Cluster Management Types Resources for cluster management are stored in the `local` cluster (the one that runs the Rancher server). The `management.cattle.io` API group indicates the resources that are backing the old Norman API. # Vuex Stores There are 3 main stores for communicating with different parts of the Rancher API: - `management`: Points at the global-level "steve" API for Rancher as a whole. - `cluster`: Points at "steve" for the one currently selected cluster; changes when you change clusters. - `rancher`: Points at the "norman" API, primally for global-level resources, but some cluster-level resources are actually stored here and not physically in the cluster to be available to the `cluster` store. And then a bunch of others: Name | For ---------------------|------- action-menu | Maintains the current selection for tables and handling bulk operations on them auth | Authentication, logging in and out, etc catalog | Stores the index data for Helm catalogs and methods to find charts, determine if upgrades are available, etc github | Part of authentication, communicating with the GitHub API growl | Global "growl" notifications in the corner of the screen i18n | Internationalization index | The root store, manages things like which cluster you're connected to and what namespaces should be shown prefs | User preferences type-map | Meta-information about all the k8s types that are available to the current user and how they should be displayed wm | "Window manager" at the bottom of the screen for things like container shells and logs. Store objects are accessed in different ways, below are common ways they are referenced by models and components |Location|type|object|example| |----|----|----|----| | `/model/` | Dispatching Actions | `this.$dispatch` | `this.$dispatch('cluster/find', { type: WORKLOAD_TYPES.JOB, id: relationship.toId }, { root: true })` | `/model/` | Access getters (store type) | `this.$getters` | `this.$getters['schemaFor'](this.type)` | `/model/` | Access getters (all) | `this.$rootGetters` | `this.$rootGetters['productId']` | component | Dispatching Actions | `this.$store.dispatch` | ``this.$store.dispatch(`${ inStore }/find`, { type: row.type, id: row.id })`` | component | Access getters | `this.$store.getters` | `this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, this.value)` > Prefixing a property in a model with `$`, as per `model` rows above, results in calling properties on the store object directly. > Troubleshooting: Fetching the name of a resource type > > Good - Trims the text and respects `.` in path to type's string - `store.getters['type-map/labelFor']({ id: NORMAN.SPOOFED.GROUP_PRINCIPAL }, 2)` > > Bad - Does not trim text, issues when resource type contains "`.`" - ``store.getters['i18n/t'](`typeLabel.${ NORMAN.SPOOFED.GROUP_PRINCIPAL }`, { count: 2 })`` ## Checking User Permissions with Schemas The schema can be checked in the Rancher API at: ``` https:///create', )`| Creates a new Proxy object of the required type (`type` property must be included in the new object) | | `clone` | Clone | `$store.$dispatch('/clone', { resource: })` | Performs a deep clone and creates a proxy from it | | `findAll` | Fetch all of a resource type and watch for changes to the returned resources so that the list updates as it changes. | `$store.dispatch('/findAll', { type: })` | Fetches all resources of the given type. Also, when applicable, will register the type for automatic updates. If the type has already been fetched return the local cached list instead | | `find` | Fetch a resource by ID and watch for changes to that individual resource. | `$store.dispatch('/find', { type: , id: })` | Finds the resource matching the ID. If the type has already been fetched return the local cached instance. | | `findMatching` | Fetch resources by label and watch for changes to the returned resources, a live array that updates as it changes. | `$store.dispatch('/findMatching', { type: , selector: