// Copyright 2019 Istio Authors
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

syntax = "proto3";

// $title: Analysis Messages
// $description: Describes the structure of messages generated by Istio analyzers.
// $location: https://istio.io/docs/reference/config/istio.analysis.v1alpha1.html
// $weight: 20

// Describes the structure of messages generated by Istio analyzers.
package istio.analysis.v1alpha1;

import "google/protobuf/struct.proto";

option go_package="istio.io/api/analysis/v1alpha1";

// There are four messages described in this file. One of them is a struct
// common to the other three: AnalysisMessageBase. Using this, we can construct
// one of three different structures.
// One is the AnalysisMessageWeakSchema, a  YAML only description of a message
// type intended to be used where strong API guarantees are not necessary.
// One is the GenericAnalysisMessage, which is the struct that we guarantee that
// you can deserialize any analysis message to. Istio internally uses generated
// golang types from messages.yaml, so in order to reduce friction in creating
// new analyzers we offer a path that doesn't require committing to two
// different repos and solidifying the interface.
// Finally, we can create a new proto message of a specific message type and
// commit it to istio/api when we need a strong guarantee for cross platform
// communication.

// AnalysisMessageBase describes some common information that is needed for all
// messages. All information should be static with respect to the error code.
message AnalysisMessageBase {
  // A unique identifier for the type of message. Name is intended to be
  // human-readable, code is intended to be machine readable. There should be a
  // one-to-one mapping between name and code. (i.e. do not re-use names or
  // codes between message types.)
  message Type {
    // A human-readable name for the message type. e.g. "InternalError",
    // "PodMissingProxy". This should be the same for all messages of the same type.
    // Required.
    string name = 1;

    // A 7 character code matching `^IST[0-9]{4}$` intended to uniquely identify
    // the message type. (e.g. "IST0001" is mapped to the "InternalError" message
    // type.) 0000-0100 are reserved. Required.
    string code = 2;
  }

  Type type = 1;

  // The values here are chosen so that more severe messages get sorted higher,
  // as well as leaving space in between to add more later
  enum Level {
    UNKNOWN = 0; // invalid, but included for proto compatibility for 0 values
    ERROR = 3;
    WARNING = 8;
    INFO = 12;
  }

  // Represents how severe a message is. Required.
  Level level = 2;

  // A url pointing to the Istio documentation for this specific error type.
  // Should be of the form
  // `^http(s)?://(preliminary\.)?istio.io/docs/reference/config/analysis/`
  // Required.
  string documentation_url = 3;

}

// AnalysisMessageWeakSchema is the set of information that's needed to define a
// weakly-typed schema. The purpose of this proto is to provide a mechanism for
// validating istio/istio/galley/pkg/config/analysis/msg/messages.yaml to make
// sure that we don't allow committing underspecified types.
message AnalysisMessageWeakSchema {
  // Required
  AnalysisMessageBase message_base = 1;

  // A human readable description of what the error means. Required.
  string description = 2;

  // A go-style template string (https://golang.org/pkg/fmt/#hdr-Printing)
  // defining how to combine the args for a  particular message into a log line.
  // Required.
  string template = 3;

  message ArgType {
    // Required
    string name = 1;
    // Required. Should be a golang type, used in code generation.
    // Ideally this will change to a less language-pinned type before this gets
    // out of alpha, but for compatibility with current istio/istio code it's
    // go_type for now.
    string go_type = 2;
  }

  // A description of the arguments for a particular message type
  repeated ArgType args = 4;
}

// GenericAnalysisMessage is an instance of an AnalysisMessage defined by a
// schema, whose metaschema is AnalysisMessageWeakSchema. (Names are hard.) Code
// should be able to perform validation of arguments as needed by using the
// message type information to look at the AnalysisMessageWeakSchema and examine the
// list of args at runtime. Developers can also create stronger-typed versions
// of GenericAnalysisMessage for well-known and stable message types.
message GenericAnalysisMessage {
  // Required
  AnalysisMessageBase message_base = 1;

  // Any message-type specific arguments that need to get codified. Optional.
  google.protobuf.Struct args = 2;

  // A list of strings specifying the resource identifiers that were the cause
  // of message generation. A "path" here is a (NAMESPACE\/)?RESOURCETYPE/NAME
  // tuple that uniquely identifies a particular resource. There doesn't seem to
  // be a single concept for this, but this is intuitively taken from
  // https://kubernetes.io/docs/reference/using-api/api-concepts/#standard-api-terminology
  // At least one is required.
  repeated string resource_paths = 3;
}

// InternalErrorAnalysisMessage is a strongly-typed message representing some
// error in Istio code that prevented us from performing analysis at all.
message InternalErrorAnalysisMessage {
  // Required
  AnalysisMessageBase message_base = 1;

  // Any detail regarding specifics of the error. Should be human-readable.
  string detail = 2;
}
