1 // -*- fill-column: 75 -*- 2 3 // Copyright 2020 Datawire. All rights reserved 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. You may obtain 7 // a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 // This file deals with common things that are shared between multiple 18 // CRDs, but are ultimately used by individual CRDs (rather than by the 19 // apiVersion as a whole). 20 21 package v3alpha1 22 23 import ( 24 "encoding/json" 25 "time" 26 ) 27 28 // V2ExplicitTLS controls some vanity/stylistic elements when converting 29 // from v3alpha1 to v2. The values in an V2ExplicitTLS should not in any 30 // way affect the runtime operation of Emissary; except that it may affect 31 // internal names in the Envoy config, which may in turn affect stats 32 // names. But it should not affect any end-user observable behavior. 33 type V2ExplicitTLS struct { 34 // TLS controls whether and how to represent the "tls" field when 35 // its value could be implied by the "service" field. In v2, there 36 // were a lot of different ways to spell an "empty" value, and this 37 // field specifies which way to spell it (and will therefore only 38 // be used if the value will indeed be empty). 39 // 40 // | Value | Representation | Meaning of representation | 41 // |--------------+---------------------------------------+------------------------------------| 42 // | "" | omit the field | defer to service (no TLSContext) | 43 // | "null" | store an explicit "null" in the field | defer to service (no TLSContext) | 44 // | "string" | store an empty string in the field | defer to service (no TLSContext) | 45 // | "bool:false" | store a Boolean "false" in the field | defer to service (no TLSContext) | 46 // | "bool:true" | store a Boolean "true" in the field | originate TLS (no TLSContext) | 47 // 48 // If the meaning of the representation contradicts anything else 49 // (if a TLSContext is to be used, or in the case of "bool:true" if 50 // TLS is not to be originated), then this field is ignored. 51 // 52 // +kubebuilder:validation:Enum={"","null","bool:true","bool:false","string"} 53 TLS string `json:"tls,omitempty"` 54 55 // ServiceScheme specifies how to spell and capitalize the scheme-part of the 56 // service URL. 57 // 58 // Acceptable values are "http://" (case-insensitive), "https://" 59 // (case-insensitive), or "". The value is used if it agrees with 60 // whether or not this resource enables TLS origination, or if 61 // something else in the resource overrides the scheme. 62 // 63 // +kubebuilder:validation:Pattern="^([hH][tT][tT][pP][sS]?://)?$" 64 ServiceScheme *string `json:"serviceScheme,omitempty"` 65 } 66 67 type CircuitBreaker struct { 68 // +kubebuilder:validation:Enum={"default", "high"} 69 Priority string `json:"priority,omitempty"` 70 MaxConnections *int `json:"max_connections,omitempty"` 71 MaxPendingRequests *int `json:"max_pending_requests,omitempty"` 72 MaxRequests *int `json:"max_requests,omitempty"` 73 MaxRetries *int `json:"max_retries,omitempty"` 74 } 75 76 // ErrorResponseTextFormatSource specifies a source for an error response body 77 type ErrorResponseTextFormatSource struct { 78 // The name of a file on the Ambassador pod that contains a format text string. 79 Filename string `json:"filename"` 80 } 81 82 // ErorrResponseOverrideBody specifies the body of an error response 83 type ErrorResponseOverrideBody struct { 84 // A format string representing a text response body. 85 // Content-Type can be set using the `content_type` field below. 86 ErrorResponseTextFormat *string `json:"text_format,omitempty"` 87 88 // A JSON response with content-type: application/json. The values can 89 // contain format text like in text_format. 90 ErrorResponseJsonFormat *map[string]string `json:"json_format,omitempty"` 91 92 // A format string sourced from a file on the Ambassador container. 93 // Useful for larger response bodies that should not be placed inline 94 // in configuration. 95 ErrorResponseTextFormatSource *ErrorResponseTextFormatSource `json:"text_format_source,omitempty"` 96 97 // The content type to set on the error response body when 98 // using text_format or text_format_source. Defaults to 'text/plain'. 99 ContentType string `json:"content_type,omitempty"` 100 } 101 102 // A response rewrite for an HTTP error response 103 type ErrorResponseOverride struct { 104 // The status code to match on -- not a pointer because it's required. 105 // +kubebuilder:validation:Required 106 // +kubebuilder:validation:Minimum=400 107 // +kubebuilder:validation:Maximum=599 108 OnStatusCode int `json:"on_status_code,omitempty"` 109 110 // The new response body 111 // +kubebuilder:validation:Required 112 Body ErrorResponseOverrideBody `json:"body,omitempty"` 113 } 114 115 // AmbassadorID declares which Ambassador instances should pay 116 // attention to this resource. If no value is provided, the default is: 117 // 118 // ambassador_id: 119 // - "default" 120 // 121 // TODO(lukeshu): In v3alpha2, consider renaming all of the `ambassador_id` (singular) fields to 122 // `ambassador_ids` (plural). 123 type AmbassadorID []string 124 125 func (aid AmbassadorID) Matches(envVar string) bool { 126 if len(aid) == 0 { 127 aid = []string{"default"} 128 } 129 for _, item := range aid { 130 if item == envVar { 131 return true 132 } 133 } 134 return false 135 } 136 137 // TODO(lukeshu): In v3alpha2, change all of the `{foo}_ms`/`MillisecondDuration` fields to 138 // `{foo}`/`metav1.Duration`. 139 // 140 // +kubebuilder:validation:Type="integer" 141 type MillisecondDuration struct { 142 time.Duration `json:"-"` 143 } 144 145 func (d *MillisecondDuration) UnmarshalJSON(data []byte) error { 146 if string(data) == "null" { 147 d.Duration = 0 148 return nil 149 } 150 151 var intval int64 152 if err := json.Unmarshal(data, &intval); err != nil { 153 return err 154 } 155 d.Duration = time.Duration(intval) * time.Millisecond 156 return nil 157 } 158 159 func (d MillisecondDuration) MarshalJSON() ([]byte, error) { 160 return json.Marshal(d.Milliseconds()) 161 } 162 163 // TODO(lukeshu): In v3alpha2, change all of the `{foo}s`/`SecondDuration` fields to 164 // `{foo}`/`metav1.Duration`. 165 // 166 // +kubebuilder:validation:Type="integer" 167 type SecondDuration struct { 168 time.Duration `json:"-"` 169 } 170 171 func (d *SecondDuration) UnmarshalJSON(data []byte) error { 172 if string(data) == "null" { 173 d.Duration = 0 174 return nil 175 } 176 177 var intval int64 178 if err := json.Unmarshal(data, &intval); err != nil { 179 return err 180 } 181 d.Duration = time.Duration(intval) * time.Second 182 return nil 183 } 184 185 func (d SecondDuration) MarshalJSON() ([]byte, error) { 186 return json.Marshal(int64(d.Seconds())) 187 } 188 189 // UntypedDict is relatively opaque as a Go type, but it preserves its 190 // contents in a roundtrippable way. 191 // 192 // +kubebuilder:validation:Type="object" 193 // +kubebuilder:pruning:PreserveUnknownFields 194 type UntypedDict struct { 195 // We have to hide this from controller-gen inside of a struct 196 // (instead of just `type UntypedDict map[string]json.RawMessage`) 197 // so that controller-gen doesn't generate an `items` field in the 198 // schema. 199 Values map[string]json.RawMessage `json:"-"` 200 } 201 202 func (u UntypedDict) MarshalJSON() ([]byte, error) { 203 return json.Marshal(u.Values) 204 } 205 206 func (u *UntypedDict) UnmarshalJSON(data []byte) error { 207 return json.Unmarshal(data, &u.Values) 208 } 209