-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gNOI OS - service that provides an interface for OS installation on a Target #19
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,326 @@ | ||
// This file defines a gNOI API used for OS installation. | ||
syntax = "proto3"; | ||
|
||
package gnoi.os; | ||
|
||
import "github.com/openconfig/gnoi/types/types.proto"; | ||
|
||
option (types.gnoi_version) = "0.1.0"; | ||
|
||
// The OS service provides an interface for OS installation on a Target. The | ||
// Client progresses through 3 RPCs: | ||
// 1) Installation - provide the Target with the OS package. | ||
// 2) Activation - activate an installed OS package. | ||
// 3) Verification - verify that the Activation was successful. | ||
// | ||
// Dual Supervisor Target is supported, where the above process is executed once | ||
// for each Supervisor. | ||
// | ||
// Note that certain platforms may have particular approaches to upgrade the | ||
// firmware of specific components, eg., power supply units, etc.. In addition, | ||
// platforms may have processes to apply patches to the running OS. Handling | ||
// these exceptions introduces extra complexities. For Targets that implement | ||
// this service, component firmware upgrade or OS patching MUST be embedded | ||
// within an OS upgrade. | ||
service OS { | ||
// Install transfers an OS package into the Target. No concurrent Install RPCs | ||
// MUST be allowed to the same Target. | ||
// | ||
// The OS package file format is platform dependent. The platform MUST | ||
// validate that the OS package that is supplied is valid and bootable. This | ||
// SHOULD include a hash check against a known good hash. It is recommended | ||
// that the hash is embedded in the OS package. | ||
// | ||
// The Target manages its own persistent storage, and OS installation process. | ||
// It stores a set of distinct OS packages, and always proactively frees up | ||
// space for incoming new OS packages. It is guaranteed that the Target always | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, to be clear the expectation is that apart from the current running OS version, any other packages may be arbitrarily deleted by starting a transfer request? Just want to make sure that that is the expectation and that the loss of control is ok. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. The Operator must not have the expectation that the Target is keeping every installed package besides the last installed one, or the active one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So when installing a package, the last installed package (if it's not the running one) can be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. However, (and this is up to the platform implementation) if the size of the storage is orders of magnitude larger than the typical size of the package, there is value in keeping a buffer of packages. The logic for removing installed packages could for example be FIFO. All of this is up to the platform implementer and out of the scope of this service. All the Client must expect is that the last Installed package is always available. I will make this clearer in the wording. |
||
// has enough space for a valid incoming OS package. The currently running OS | ||
// packages MUST never be removed. The Client MUST expect that the last | ||
// successfully installed package is available. | ||
// | ||
// The Install RPC allows the Client to specify the OS package version. If | ||
// the Target already has an OS package with the same version then there is no | ||
// need to transfer the OS package to the Target. If the Target does not have | ||
// an OS package with the same version, then the OS package is copied. | ||
// | ||
// Scenario 1 - When the Target already has the OS package: | ||
// | ||
// Client :--------------|--------------> Target | ||
// TransferRequest --> | ||
// <-- [Validated|InstallError] | ||
// | ||
// | ||
// Scenario 2 - When the Target does not have the OS package: | ||
// | ||
// Client :--------------|--------------> Target | ||
// TransferRequest --> | ||
// <-- [TransferReady|InstallError] | ||
// transfer_content --> | ||
// ... | ||
// <-- [TransferProgress|InstallError] | ||
// ... | ||
// TransferEnd --> | ||
// <-- [Validated|InstallError] | ||
// | ||
// On a dual Supervisor Target, only the Active Supervisor runs this gNOI | ||
// Service. The Install RPC applies to the Active Supervisor unless | ||
// InstallRequest->TransferRequest->standby_supervisor is set, in which case | ||
// it applies to the Standby Supervisor. One Install RPC is required for each | ||
// Supervisor. The Supervisor order of package installation MUST not be fixed. | ||
// | ||
// The Target MUST always attempt to copy the OS package between Supervisors | ||
// first before accepting the transfer from the Client. The syncing progress | ||
// is reported to the client with InstallResponse->SyncProgress messages. | ||
// | ||
// If a switchover is triggered during the Install RPC, the RPC MUST | ||
// immediately abort with Error->type->UNEXPECTED_SWITCHOVER. | ||
// | ||
// Scenario 3 - When both Supervisors already have the OS package, regardless | ||
// of the value in Start.standby_supervisor: | ||
// | ||
// Client :--------------|--------------> Target | ||
// TransferRequest --> | ||
// <-- [Validated|InstallError] | ||
// | ||
// | ||
// Scenario 4 - When one of the Supervisors already has the OS package but the | ||
// other Supervisor is the target of the Install: | ||
// | ||
// Client :--------------|--------------> Target | ||
// TransferRequest --> | ||
// <-- [SyncProgress|InstallError] | ||
// ... | ||
// <-- [Validated|InstallError] | ||
// | ||
// | ||
// Scenario 5 - When neither of the two Supervisors has the OS package: | ||
// | ||
// Client :--------------|--------------> Target | ||
// TransferRequest --> | ||
// <-- [TransferReady|InstallError] | ||
// transfer_content --> | ||
// ... | ||
// <-- [TransferProgress|InstallError] | ||
// ... | ||
// TransferEnd --> | ||
// <-- [Validated|InstallError] | ||
// | ||
rpc Install(stream InstallRequest) returns (stream InstallResponse); | ||
|
||
// Activate sets the requested OS version as the version which is used at the | ||
// next reboot, and reboots the Target. When booting the requested OS version | ||
// fails, the Target recovers by booting the previously running OS package. | ||
rpc Activate(ActivateRequest) returns (ActivateResponse); | ||
|
||
// Verify checks the running OS version. This RPC may be called multiple times | ||
// while the Target boots, until successful. | ||
rpc Verify(VerifyRequest) returns (VerifyResponse); | ||
} | ||
|
||
message InstallRequest { | ||
oneof request { | ||
TransferRequest transfer_request = 1; | ||
bytes transfer_content = 2; | ||
TransferEnd transfer_end = 3; | ||
} | ||
} | ||
|
||
message TransferRequest { | ||
// The version string is a vendor defined string that identifies the OS | ||
// version. It is provided by the vendor and embedded in the OS package. This | ||
// value states the desired OS package version to transfer to the Target. If | ||
// the Target already has the OS package version it will reply with | ||
// InstallResponse->Validated. In the case that the target is a | ||
// single Supervisor device, or the partner Supervisor does not have the OS | ||
// image specified, it will respond with InstallResponse->TransferReady. In | ||
// this case, the client MUST subsequently transfer the image. In the case | ||
// that the image is available on the peer Supervisor of a dual Supervisor | ||
// system, it will respond with InstallResponse->SyncProgress. In this, | ||
// latter, case - the client does not need to transfer the OS image. This | ||
// value can also be set empty, in which case the OS package is forced | ||
// transferred to the Target. The Target MUST never validate that this value | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the version is empty, the target generates a version/name for the package? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The version string is always a well known OS version string builtin in the OS package and provided by the vendor. Will update text. thanks! |
||
// matches the one in the InstallResponse->Validated message, that is the | ||
// Client's responsibility. | ||
string version = 1; | ||
|
||
// For a Target with dual Supervisors setting this flag instructs the Target | ||
// to perform the action on the Standby Supervisor. | ||
bool standby_supervisor = 2; | ||
} | ||
|
||
// The TransferEnd message is sent whenever the Client finishes transferring | ||
// the OS package to the Target. At this point the Target MUST perform a general | ||
// health check to the OS package. If the Target fails to parse the OS package | ||
// it MUST immediately reply with an InstallError->type->PARSE_FAIL. If the | ||
// integrity check of the OS package fails it MUST immediately reply with an | ||
// InstallError->type->INTEGRITY_FAIL. If the identified OS version contained in | ||
// the package is not compatible with the Target either because of the platform | ||
// type or the running OS, it MUST immediately reply with an | ||
// InstallError->type->INCOMPATIBLE. If the image is force transferred by | ||
// omitting the InstallRequest->TransferRequest->version value, and the OS | ||
// package is the same as the one running in the Target, the RPC MUST | ||
// immediately abort and reply with an InstallError->type->INSTALL_RUN_PACKAGE. | ||
message TransferEnd {} | ||
|
||
// The InstallResponse is used by the Target to inform the Client about the | ||
// state of the Install RPC. At any stage of the process the Target can reply | ||
// with an Error message which MUST terminate the stream. | ||
message InstallResponse { | ||
oneof response { | ||
TransferReady transfer_ready = 1; | ||
TransferProgress transfer_progress = 2; | ||
SyncProgress sync_progress = 3; | ||
Validated validated = 4; | ||
InstallError install_error = 5; | ||
} | ||
} | ||
|
||
// The TransferReady message tells the Client that the Target is ready to accept | ||
// the transfer of the OS package. At this stage the Target MUST have cleared | ||
// enough space to accept the incoming OS package. | ||
message TransferReady {} | ||
|
||
// The TransferProgress message is sent by the target asynchronously during a | ||
// file transfer. The device SHOULD not respond to each input block received | ||
// from the client, but rather determine reasonable intervals at which to send | ||
// the message (e.g., 5MB). | ||
message TransferProgress { | ||
// The number of bytes transferred. | ||
uint64 bytes_received = 1; | ||
} | ||
|
||
// The SyncProgress message signals the Client about the progress of | ||
// transferring the OS package between Supervisors. | ||
message SyncProgress { | ||
// The percentage that has transferred between Supervisors. | ||
uint32 percentage_transferred = 1; | ||
} | ||
|
||
// The Validated message asserts that the Target was able to parse the package | ||
// and perform integrity checks to its contents. | ||
message Validated { | ||
// The OS version string that identifies the OS version in the OS package. | ||
string version = 1; | ||
// Informational field that SHOULD be used for providing more details about | ||
// the OS package and its version. This MUST be strictly informational if | ||
// used, and can contain information such as build date, target platform, | ||
// developer, etc. | ||
string description = 2; | ||
} | ||
|
||
// The InstallError message MUST be sent by the Target to the Client whenever an | ||
// issue occurs. The Target MUST immediately close the RPC without a gRPC error. | ||
message InstallError { | ||
enum Type { | ||
// An unspecified error. Must use the detail value to describe the issue. | ||
UNSPECIFIED = 0; | ||
// The newly transferred package is not compatible with the Target platform. | ||
// The detail field MUST contain the detailed error message. | ||
INCOMPATIBLE = 1; | ||
// The OS package being transferred is larger than the available size the | ||
// Target provisioned. This is unexpected since the Target MUST clear disk | ||
// space for the new OS packages. The available space and the OS package | ||
// size MUST be guaranteed by the platform maker, therefore the most likely | ||
// cause of this error is that a wrong package is being transferred. | ||
TOO_LARGE = 2; | ||
// Used whenever the system is unable to parse the newly transferred | ||
// package, like reading the OS version or the integrity checksums. | ||
PARSE_FAIL = 3; | ||
// The transferred OS package fails integrity check. | ||
INTEGRITY_FAIL = 4; | ||
// Attempting to force transfer an OS package with the same version as the | ||
// currently running. | ||
INSTALL_RUN_PACKAGE = 5; | ||
// Another Install RPC to this Target is already in progress. | ||
INSTALL_IN_PROGRESS = 6; | ||
// A switchover happened during the Install RPC. | ||
UNEXPECTED_SWITCHOVER = 7; | ||
// Failed to sync the transferred OS package to the standby Supervisor. The | ||
// detail value MUST have more information. | ||
SYNC_FAIL = 8; | ||
} | ||
Type type = 1; | ||
string detail = 2; | ||
} | ||
|
||
// The ActivateRequest is sent by the Client to the Target to initiate a change | ||
// in the next bootable OS version that is to be used on the Target. | ||
message ActivateRequest { | ||
// The version that is required to be activated and booted. | ||
string version = 1; | ||
// For dual Supervisors setting this flag instructs the Target to perform the | ||
// action on the Standby Supervisor. | ||
bool standby_supervisor = 2; | ||
} | ||
|
||
// The ActivateResponse is sent from the Target to the Client in response to the | ||
// Activate RPC. It indicates the success of making the OS package version | ||
// active. | ||
message ActivateResponse { | ||
oneof response { | ||
ActivateOK activate_ok = 1; | ||
ActivateError activate_error = 2; | ||
} | ||
} | ||
|
||
// If the Target is already running the requested version in ActivateRequest, | ||
// then it replies with ActivateOK. If the Target has the OS package version | ||
// requested in ActivateRequest then it replies with ActivateOK and proceeds to | ||
// boot. In a Target with dual Supervisor, performing this RPC on the Active | ||
// Supervisor triggers a switchover before booting the (old)Active Supervisor. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So with a dual supervisor, the requirement is to do an ISSU upgrade? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe ISSU upgrade is a bit more involved. This is just stating that if standby_supervisor = False, Then the Active Supervisor is the Target of the package activation, regardless of the active package in the Standby Supervisor. Because the Active Supervisor is rebooting, a switchover needs to happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks Sam. So the image activation specified here doesn't require ISSU upgrade? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The platform should always attempt performing a failover with the least impact possible. I will update the text. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this does not answer your question. The answer is out of of scope of this service. The switchover behavior in regards to non stop forwarding should be a customer to vendor conversation. ISSU is rather specific and packages upgrade and switchover behavior together. |
||
// The Target should always perform a switchover with the least impact possible | ||
// to forwarding. | ||
message ActivateOK {} | ||
|
||
message ActivateError { | ||
enum Type { | ||
// An unspecified error. Must use the detail value to describe the issue. | ||
UNSPECIFIED = 0; | ||
// There is no OS package with the version requested for activation. This is | ||
// also used for an empty version string. | ||
NON_EXISTENT_VERSION = 1; | ||
} | ||
Type type = 1; | ||
string detail = 2; | ||
} | ||
|
||
message VerifyRequest {} | ||
|
||
message VerifyResponse { | ||
// The OS version currently running. | ||
string version = 1; | ||
// Informational message describing fail details of the last boot. This MUST | ||
// be set when a newly transferred OS fails to boot and the system falls back | ||
// to the previously running OS version. It MUST be cleared whenever the | ||
// systems successfully boots the activated OS version. | ||
string activation_fail_message = 2; | ||
|
||
VerifyStandby verify_standby = 3; | ||
} | ||
|
||
message VerifyStandby { | ||
oneof state { | ||
StandbyState standby_state = 1; | ||
StandbyResponse verify_response = 2; | ||
} | ||
} | ||
|
||
message StandbyState { | ||
enum State { | ||
UNSPECIFIED = 0; | ||
// The Target does not support dual Supervisors. | ||
UNSUPORTED = 1; | ||
// Standby Supervisor is supported but does not exist. | ||
NON_EXISTENT = 2; | ||
// Standby Supervisor is supported but is not available, eg.: rebooting. | ||
UNAVAILABLE = 3; | ||
} | ||
State state = 1; | ||
} | ||
|
||
message StandbyResponse { | ||
// Standby Supervisor ID, usually the slot number. | ||
string id = 1; | ||
string version = 2; | ||
string activation_fail_message = 3; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a common way that a failure due to not allowing concurrent requests should be signaled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, line 232: InstallResponse->InstallError->INSTALL_IN_PROGRESS