Merge "Returns CNI errors in specified form"
This commit is contained in:
commit
4ce01a7908
|
@ -14,7 +14,6 @@ import (
|
||||||
cni "github.com/containernetworking/cni/pkg/types"
|
cni "github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -24,6 +23,9 @@ const (
|
||||||
urlBase = "http://localhost:5036/"
|
urlBase = "http://localhost:5036/"
|
||||||
addPath = "addNetwork"
|
addPath = "addNetwork"
|
||||||
delPath = "delNetwork"
|
delPath = "delNetwork"
|
||||||
|
|
||||||
|
ErrVif uint = 899
|
||||||
|
ErrParsing uint = 799
|
||||||
)
|
)
|
||||||
|
|
||||||
type KuryrDaemonData struct {
|
type KuryrDaemonData struct {
|
||||||
|
@ -40,7 +42,12 @@ func transformData(args *skel.CmdArgs, command string) (KuryrDaemonData, error)
|
||||||
var conf interface{}
|
var conf interface{}
|
||||||
err := json.Unmarshal(args.StdinData, &conf)
|
err := json.Unmarshal(args.StdinData, &conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return KuryrDaemonData{}, err
|
newErr := types.Error{
|
||||||
|
Code: types.ErrDecodingFailure,
|
||||||
|
Msg: fmt.Sprintf("Error when reading configuration: %v", err),
|
||||||
|
Details: "",
|
||||||
|
}
|
||||||
|
return KuryrDaemonData{}, &newErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return KuryrDaemonData{
|
return KuryrDaemonData{
|
||||||
|
@ -59,7 +66,11 @@ func makeDaemonRequest(data KuryrDaemonData, expectedCode int) ([]byte, error) {
|
||||||
|
|
||||||
b, err := json.Marshal(data)
|
b, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, errors.Wrapf(err, "Error when preparing payload for kuryr-daemon")
|
return []byte{}, &types.Error{
|
||||||
|
Code: types.ErrInvalidNetworkConfig,
|
||||||
|
Msg: fmt.Sprintf("Error when preparing payload for kuryr-daemon: %v", err),
|
||||||
|
Details: "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url := ""
|
url := ""
|
||||||
|
@ -69,27 +80,43 @@ func makeDaemonRequest(data KuryrDaemonData, expectedCode int) ([]byte, error) {
|
||||||
case "DEL":
|
case "DEL":
|
||||||
url = urlBase + delPath
|
url = urlBase + delPath
|
||||||
default:
|
default:
|
||||||
return []byte{}, errors.Errorf("Cannot handle command %s", data.Command)
|
return []byte{}, &types.Error{
|
||||||
|
Code: types.ErrInvalidEnvironmentVariables,
|
||||||
|
Msg: fmt.Sprintf("Cannot handle command %s", data.Command),
|
||||||
|
Details: "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := http.Post(url, "application/json", bytes.NewBuffer(b))
|
resp, err := http.Post(url, "application/json", bytes.NewBuffer(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, errors.Wrapf(err, "Looks like %s cannot be reached. Is kuryr-daemon running?", url)
|
return []byte{}, &types.Error{
|
||||||
|
Code: types.ErrTryAgainLater,
|
||||||
|
Msg: fmt.Sprintf("Looks like %s cannot be reached. Is kuryr-daemon running?", url),
|
||||||
|
Details: fmt.Sprintf("%v", err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
if resp.StatusCode != expectedCode {
|
if resp.StatusCode != expectedCode {
|
||||||
return []byte{}, errors.Errorf("CNI Daemon returned error %d %s", resp.StatusCode, body)
|
if len(body) > 1 {
|
||||||
|
var err types.Error
|
||||||
|
json.Unmarshal(body, &err)
|
||||||
|
return []byte{}, &err
|
||||||
|
}
|
||||||
|
return []byte{}, &types.Error{
|
||||||
|
Code: uint(resp.StatusCode),
|
||||||
|
Msg: fmt.Sprintf("CNI Daemon returned error %d %s", resp.StatusCode, body),
|
||||||
|
Details: "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdAdd(args *skel.CmdArgs) error {
|
func cmdAdd(args *skel.CmdArgs) error {
|
||||||
data, err := transformData(args, "ADD")
|
data, err := transformData(args, "ADD")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error when reading configuration")
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := makeDaemonRequest(data, 202)
|
body, err := makeDaemonRequest(data, 202)
|
||||||
|
@ -98,9 +125,13 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
vif := VIF{}
|
vif := VIF{}
|
||||||
err = json.Unmarshal(body, &vif)
|
er := json.Unmarshal(body, &vif)
|
||||||
if err != nil {
|
if er != nil {
|
||||||
return errors.Wrapf(err, "Error when reading response from kuryr-daemon: %s", string(body))
|
return &types.Error{
|
||||||
|
Code: ErrVif,
|
||||||
|
Msg: fmt.Sprintf("Error when reading response from kuryr-daemon: %s", string(body)),
|
||||||
|
Details: fmt.Sprintf("%v", er),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iface := current.Interface{}
|
iface := current.Interface{}
|
||||||
|
@ -115,13 +146,19 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||||
addrStr := subnet.Ips[0].Address
|
addrStr := subnet.Ips[0].Address
|
||||||
addr := net.ParseIP(addrStr)
|
addr := net.ParseIP(addrStr)
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return errors.Errorf("Error when parsing IP address %s received from kuryr-daemon", addrStr)
|
return &types.Error{
|
||||||
|
Code: ErrParsing,
|
||||||
|
Msg: fmt.Sprintf("Error when parsing IP address %s received from kuryr-daemon", addrStr),
|
||||||
|
Details: "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_, cidr, err := net.ParseCIDR(subnet.Cidr)
|
_, cidr, err := net.ParseCIDR(subnet.Cidr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "Error when parsing CIDR %s received from kuryr-daemon",
|
return &types.Error{
|
||||||
subnet.Cidr)
|
Code: ErrParsing,
|
||||||
|
Msg: fmt.Sprintf("Error when parsing CIDR %s received from kuryr-daemon", subnet.Cidr),
|
||||||
|
Details: fmt.Sprintf("%v", err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ver := "4"
|
ver := "4"
|
||||||
|
@ -133,7 +170,11 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||||
ifaceCIDR := fmt.Sprintf("%s/%d", addr.String(), prefixSize)
|
ifaceCIDR := fmt.Sprintf("%s/%d", addr.String(), prefixSize)
|
||||||
ipAddress, err := cni.ParseCIDR(ifaceCIDR)
|
ipAddress, err := cni.ParseCIDR(ifaceCIDR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "Error when parsing CIDR %s received from kuryr-daemon", ifaceCIDR)
|
return &types.Error{
|
||||||
|
Code: ErrParsing,
|
||||||
|
Msg: fmt.Sprintf("Error when parsing CIDR %s received from kuryr-daemon", ifaceCIDR),
|
||||||
|
Details: fmt.Sprintf("%v", err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ifaceNum := 0
|
ifaceNum := 0
|
||||||
|
|
||||||
|
@ -147,14 +188,20 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||||
for _, route := range subnet.Routes {
|
for _, route := range subnet.Routes {
|
||||||
_, dst, err := net.ParseCIDR(route.Cidr)
|
_, dst, err := net.ParseCIDR(route.Cidr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "Error when parsing CIDR %s received from kuryr-daemon",
|
return &types.Error{
|
||||||
route.Cidr)
|
Code: ErrParsing,
|
||||||
|
Msg: fmt.Sprintf("Error when parsing CIDR %s received from kuryr-daemon", route.Cidr),
|
||||||
|
Details: fmt.Sprintf("%v", err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gw := net.ParseIP(route.Gateway)
|
gw := net.ParseIP(route.Gateway)
|
||||||
if gw == nil {
|
if gw == nil {
|
||||||
return errors.Errorf("Error when parsing IP address %s received from kuryr-daemon",
|
return &types.Error{
|
||||||
route.Gateway)
|
Code: ErrParsing,
|
||||||
|
Msg: fmt.Sprintf("Error when parsing IP address %s received from kuryr-daemon", route.Gateway),
|
||||||
|
Details: "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routes = append(routes, &types.Route{Dst: *dst, GW: gw})
|
routes = append(routes, &types.Route{Dst: *dst, GW: gw})
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from ctypes import c_bool
|
from ctypes import c_bool
|
||||||
|
import errno
|
||||||
from http import client as httplib
|
from http import client as httplib
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
|
@ -25,6 +26,7 @@ import urllib3
|
||||||
|
|
||||||
import cotyledon
|
import cotyledon
|
||||||
import flask
|
import flask
|
||||||
|
import pyroute2
|
||||||
from pyroute2.ipdb import transactional
|
from pyroute2.ipdb import transactional
|
||||||
|
|
||||||
import os_vif
|
import os_vif
|
||||||
|
@ -48,6 +50,9 @@ from kuryr_kubernetes import watcher as k_watcher
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
HEALTH_CHECKER_DELAY = 5
|
HEALTH_CHECKER_DELAY = 5
|
||||||
|
ErrInvalidEnvironmentVariables = 4
|
||||||
|
ErrTryAgainLater = 11
|
||||||
|
ErrInternal = 999
|
||||||
|
|
||||||
|
|
||||||
class DaemonServer(object):
|
class DaemonServer(object):
|
||||||
|
@ -70,26 +75,64 @@ class DaemonServer(object):
|
||||||
params.CNI_COMMAND, params)
|
params.CNI_COMMAND, params)
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
def _error(self, error_code, message, details=""):
|
||||||
|
template = {
|
||||||
|
"code": error_code,
|
||||||
|
"msg": message,
|
||||||
|
"details": details
|
||||||
|
}
|
||||||
|
data = jsonutils.dumps(template)
|
||||||
|
return data
|
||||||
|
|
||||||
def add(self):
|
def add(self):
|
||||||
try:
|
try:
|
||||||
params = self._prepare_request()
|
params = self._prepare_request()
|
||||||
except Exception:
|
except Exception:
|
||||||
self._check_failure()
|
self._check_failure()
|
||||||
LOG.exception('Exception when reading CNI params.')
|
LOG.exception('Exception when reading CNI params.')
|
||||||
return '', httplib.BAD_REQUEST, self.headers
|
error = self._error(ErrInvalidEnvironmentVariables,
|
||||||
|
"Required CNI params missing.")
|
||||||
|
return error, httplib.BAD_REQUEST, self.headers
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vif = self.plugin.add(params)
|
vif = self.plugin.add(params)
|
||||||
data = jsonutils.dumps(vif.obj_to_primitive())
|
data = jsonutils.dumps(vif.obj_to_primitive())
|
||||||
except exceptions.ResourceNotReady:
|
except exceptions.ResourceNotReady as e:
|
||||||
self._check_failure()
|
self._check_failure()
|
||||||
LOG.error('Error when processing addNetwork request')
|
LOG.error('Error when processing addNetwork request')
|
||||||
return '', httplib.GATEWAY_TIMEOUT, self.headers
|
error = self._error(ErrTryAgainLater,
|
||||||
|
f"{e}. Try Again Later.")
|
||||||
|
return error, httplib.GATEWAY_TIMEOUT, self.headers
|
||||||
|
except pyroute2.NetlinkError as e:
|
||||||
|
if e.code == errno.EEXIST:
|
||||||
|
self._check_failure()
|
||||||
|
args = {'kind': 'vlan', 'vlan_id': vif.vlan_id}
|
||||||
|
LOG.warning(
|
||||||
|
f'Creation of pod interface failed due to VLAN ID '
|
||||||
|
f'(vlan_info={args}) conflict. Probably the CRI had not '
|
||||||
|
f'cleaned up the network namespace of deleted pods. '
|
||||||
|
f'Attempting to retry.')
|
||||||
|
error = self._error(ErrTryAgainLater,
|
||||||
|
"Creation of pod interface failed due to"
|
||||||
|
" vlan_id. Try Again Later",
|
||||||
|
f"vlan_id:{vif.vlan_id}")
|
||||||
|
return error, httplib.GATEWAY_TIMEOUT, self.headers
|
||||||
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
self._check_failure()
|
if not self.healthy.value:
|
||||||
|
error = self._error(ErrInternal,
|
||||||
|
"Maximum CNI ADD Failures Reached.",
|
||||||
|
"Error when processing addNetwork request."
|
||||||
|
" CNI Params: {}".format(params))
|
||||||
|
else:
|
||||||
|
self._check_failure()
|
||||||
|
error = self._error(ErrInternal,
|
||||||
|
"Error processing request",
|
||||||
|
"Failure processing addNetwork request. "
|
||||||
|
"CNI Params: {}".format(params))
|
||||||
LOG.exception('Error when processing addNetwork request. CNI '
|
LOG.exception('Error when processing addNetwork request. CNI '
|
||||||
'Params: %s', params)
|
'Params: %s', params)
|
||||||
return '', httplib.INTERNAL_SERVER_ERROR, self.headers
|
return error, httplib.INTERNAL_SERVER_ERROR, self.headers
|
||||||
|
|
||||||
return data, httplib.ACCEPTED, self.headers
|
return data, httplib.ACCEPTED, self.headers
|
||||||
|
|
||||||
|
@ -98,7 +141,9 @@ class DaemonServer(object):
|
||||||
params = self._prepare_request()
|
params = self._prepare_request()
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception('Exception when reading CNI params.')
|
LOG.exception('Exception when reading CNI params.')
|
||||||
return '', httplib.BAD_REQUEST, self.headers
|
error = self._error(ErrInvalidEnvironmentVariables,
|
||||||
|
"Required CNI params missing.")
|
||||||
|
return error, httplib.BAD_REQUEST, self.headers
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.plugin.delete(params)
|
self.plugin.delete(params)
|
||||||
|
@ -112,10 +157,20 @@ class DaemonServer(object):
|
||||||
'Ignoring this error, pod is most likely gone')
|
'Ignoring this error, pod is most likely gone')
|
||||||
return '', httplib.NO_CONTENT, self.headers
|
return '', httplib.NO_CONTENT, self.headers
|
||||||
except Exception:
|
except Exception:
|
||||||
self._check_failure()
|
if not self.healthy.value:
|
||||||
|
error = self._error(ErrInternal,
|
||||||
|
"Maximum CNI DEL Failures Reached.",
|
||||||
|
"Error processing delNetwork request. "
|
||||||
|
"CNI Params: {}".format(params))
|
||||||
|
else:
|
||||||
|
self._check_failure()
|
||||||
|
error = self._error(ErrInternal,
|
||||||
|
"Error processing request",
|
||||||
|
"Failure processing delNetwork request. "
|
||||||
|
"CNI Params: {}".format(params))
|
||||||
LOG.exception('Error when processing delNetwork request. CNI '
|
LOG.exception('Error when processing delNetwork request. CNI '
|
||||||
'Params: %s.', params)
|
'Params: %s.', params)
|
||||||
return '', httplib.INTERNAL_SERVER_ERROR, self.headers
|
return error, httplib.INTERNAL_SERVER_ERROR, self.headers
|
||||||
return '', httplib.NO_CONTENT, self.headers
|
return '', httplib.NO_CONTENT, self.headers
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
Loading…
Reference in New Issue