diff --git a/confluent_server/confluent/httpapi.py b/confluent_server/confluent/httpapi.py index 669411f9..aac460a7 100644 --- a/confluent_server/confluent/httpapi.py +++ b/confluent_server/confluent/httpapi.py @@ -30,6 +30,7 @@ import confluent.log as log import confluent.messages import confluent.core as pluginapi import confluent.asynchttp +import confluent.selfservice as selfservice import confluent.shellserver as shellserver import confluent.tlvdata import confluent.util as util @@ -419,6 +420,10 @@ def resourcehandler_backend(env, start_response): if 'restexplorerop' in querydict: operation = querydict['restexplorerop'] del querydict['restexplorerop'] + if env.get('PATH_INFO', '').startswith('/self/'): + for res in selfservice.handle_request(env, operation, start_response): + yield res + return authorized = _authorize_request(env, operation) if 'logout' in authorized: start_response('200 Successful logout', headers) diff --git a/confluent_server/confluent/netutil.py b/confluent_server/confluent/netutil.py index ca7d05fe..0bd5345c 100644 --- a/confluent_server/confluent/netutil.py +++ b/confluent_server/confluent/netutil.py @@ -85,9 +85,31 @@ def _rebuildidxmap(): ci = int(open('/sys/class/net/{0}/ifindex'.format(iname)).read()) _idxtoifnamemap[ci] = iname + +def myiptonets(svrip): + fam = netifaces.AF_INET + if ':' in svrip: + fam = netifaces.AF_INET6 + relevantnic = None + for iface in netifaces.interfaces(): + for addr in netifaces.ifaddresses(iface).get(fam, []): + addr = addr.get('addr', '') + addr = addr.split('%')[0] + if addresses_match(addr, svrip): + relevantnic = iface + break + else: + continue + break + return inametonets(relevantnic) + + def idxtonets(ifidx): _rebuildidxmap() iname = _idxtoifnamemap.get(ifidx, None) + return inametonets(iname) + +def inametonets(iname): addrs = netifaces.ifaddresses(iname) try: addrs = addrs[netifaces.AF_INET] @@ -98,7 +120,7 @@ def idxtonets(ifidx): mask = struct.unpack('!I', socket.inet_aton(addr['netmask']))[0] net = ip & mask net = socket.inet_ntoa(struct.pack('!I', net)) - yield (net, mask_to_cidr(addr['netmask'])) + yield (net, mask_to_cidr(addr['netmask']), addr['addr']) # TODO(jjohnson2): have a method to arbitrate setting methods, to aid # in correct matching of net.* based on parameters, mainly for pxe @@ -109,7 +131,8 @@ def idxtonets(ifidx): # that mac address # the ip as reported by recvmsg to match the subnet of that net.* interface # if switch and port available, that should match. -def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None): +def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None, + serverip=None): """Fetch network configuration parameters for a nic For a given node and interface, find and retrieve the pertinent network @@ -148,13 +171,24 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None): 'ipv4_address': None, 'ipv4_method': None, 'prefix': None, + 'ipv4_server': None, } + nets = None + needsvrip = False if ifidx is not None: dhcprequested = False nets = list(idxtonets(ifidx)) + if serverip is not None: + needsvrip = True + dhcprequested = False + nets = list(myiptonets(serverip)) + if nets is not None: candgws = [] + candsrvs = [] for net in nets: - net, prefix = net + net, prefix, svrip = net + candsrvs.append(svrip) + cfgdata['ipv4_server'] = svrip for candidate in cfgbyname: if cfgbyname[candidate].get('ipv4_method', None) == 'dhcp': dhcprequested = True @@ -185,12 +219,16 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None): except Exception: return cfgdata for net in nets: - net, prefix = net + net, prefix, svrip = net if ip_on_same_subnet(net, ipbynodename, prefix): cfgdata['ipv4_address'] = ipbynodename cfgdata['ipv4_method'] = 'static' cfgdata['prefix'] = prefix break + for svr in candsrvs: + if ip_on_same_subnet(svr, ipbynodename, prefix): + cfgdata['ipv4_server'] = svr + break for gw in candgws: if ip_on_same_subnet(gw, ipbynodename, prefix): cfgdata['ipv4_gateway'] = gw diff --git a/confluent_server/confluent/selfservice.py b/confluent_server/confluent/selfservice.py new file mode 100644 index 00000000..9cf61e4f --- /dev/null +++ b/confluent_server/confluent/selfservice.py @@ -0,0 +1,63 @@ +import confluent.config.configmanager as configmanager +import confluent.netutil as netutil +import crypt +import json +import yaml + + +def yamldump(input): + return yaml.dump(input, default_flow_style=False) + + +def handle_request(env, operation, start_response): + nodename = env.get('HTTP_CONFLUENT_NODENAME', None) + apikey = env.get('HTTP_CONFLUENT_APIKEY', None) + if not (nodename and apikey): + start_response('401 Unauthorized', []) + yield 'Unauthorized' + return + cfg = configmanager.ConfigManager(None) + eak = cfg.get_node_attributes(nodename, 'api.key').get( + nodename, {}).get('api.key', {}).get('value', None) + if not eak: + start_response('401 Unauthorized', []) + yield 'Unauthorized' + return + salt = '$'.join(eak.split('$', 3)[:-1]) + '$' + if crypt.crypt(apikey, salt) != eak: + start_response('401 Unauthorized', []) + yield 'Unauthorized' + return + retype = env.get('HTTP_ACCEPT', 'application/yaml') + if retype == '*/*': + retype = 'application/yaml' + if retype == 'application/yaml': + dumper = yamldump + elif retype == 'application/json': + dumper = json.dumps + else: + start_response('406 Not supported', []) + yield 'Unsupported content type in ACCEPT: ' + retype + return + if env['PATH_INFO'] == '/self/deploycfg': + myip = env.get('HTTP_X_FORWARDED_HOST', None) + myip = myip.replace('[', '').replace(']', '') + ncfg = netutil.get_nic_config(cfg, nodename, serverip=myip) + if ncfg['prefix']: + ncfg['ipv4_netmask'] = netutil.cidr_to_mask(ncfg['prefix']) + deployinfo = cfg.get_node_attributes(nodename, 'deployment.*') + deployinfo = deployinfo.get(nodename, {}) + profile = deployinfo.get( + 'deployment.pendingprofile', {}).get('value', '') + ncfg['profile'] = profile + protocol = deployinfo.get('deployment.useinsecureprotocols', {}).get( + 'value', 'never') + if protocol == 'always': + ncfg['protocol'] = 'http' + else: + ncfg['protocol'] = 'https' + start_response('200 OK', (('Content-Type', retype),)) + yield dumper(ncfg) + else: + start_response('404 Not Found', ()) + yield 'Not found' \ No newline at end of file diff --git a/misc/confluent-initqueue.sh.rh8 b/misc/confluent-initqueue.sh.rh8 index 8dd4e517..f7452c36 100644 --- a/misc/confluent-initqueue.sh.rh8 +++ b/misc/confluent-initqueue.sh.rh8 @@ -5,15 +5,60 @@ for currif in *; do done cd - while ! grep MANAGER /tmp/confluent.info >& /dev/null; do - /opt/confluent/bin/copernicus > /tmp/confluent.out + /opt/confluent/bin/copernicus -t > /tmp/confluent.info done read ifidx < /tmp/net.ifaces -# Need to construct the following: -# echo ip=172.30.203.31::172.30.0.254:255.255.0.0:r4u31:enp65s0f0:none >> /etc/cmdline.d/01-confluent.conf -# echo inst.repo=http://172.30.0.254/confluent-public/os/centos-8.1-x86_64-compute/distribution >> /etc/cmdline.d/01-confluent.conf +nodename=$grep ^NODENAME /tmp/confluent.info|awk '{print $2}') +#TODO: blkid --label to find mounted api + +if [ -z "$apikey" ]; then + apikey=$(/opt/confluent/bin/clortho $nodename $mgr) +fi + +curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/deploycfg > /tmp/confluent.deploycfg + +ipv4_address: 172.30.203.31 +ipv4_gateway: null +ipv4_method: static +ipv4_netmask: 255.255.0.0 +ipv4_server: 172.30.254.2 +prefix: 16 +profile: centos-8.1-x86_64-compute + +mgr=$(grep ^ipv4_server: /tmp/confluent.deploycfg) +mgr=${mgr#ipv4_server: } +profilename=$(grep ^profile: /tmp/confluent.deploycfg) +profilename=${profilename#profile: } +proto=$(grep ^protocol: /tmp/confluent.deploycfg) +proto=${proto#protocol: } +echo inst.repo=$proto://$mgr/confluent-public/os/$profilename/distribution >> /etc/cmdline.d/01-confluent.conf +echo inst.ks=$proto://$mgr/confluent-public/os/$profilename/kickstart >> /etc/cmdline.d/01-confluent.conf + +autoconfigmethod=$(grep ipv4_method /tmp/confluent.deploycfg) +autoconfigmethod=${autoconfigmethod#ipv4_method} +if [ "$autoconfigmethod" = "dhcp" ]; then + echo ip=$ifname:dhcp +else + v4addr=$(grep ^ipv4_address: /tmp/confluent.deploycfg) + v4addr=${v4addr#ipv4_address: } + v4gw=$(grep ^ipv4_gateway: /tmp/confluent.deploycfg) + v4gw=${v4gw#ipv4_gateway: } + if [ "$v4gw" = "null" ]; then + v4gw="" + fi + v4nm=$(grep ipv4_netmask: /tmp/confluent.deploycfg) + v4nm=${v4nm#ipv4_netmask: } + echo ip=$v4addr::$vpgw:$v4nm:$nodename:$ifname:none >> /etc/cmdline.d/01-confluent.conf +fi + diff --git a/misc/confluent-prepivot.sh.rh8 b/misc/confluent-prepivot.sh.rh8 index 8205406e..4c607d88 100644 --- a/misc/confluent-prepivot.sh.rh8 +++ b/misc/confluent-prepivot.sh.rh8 @@ -1,2 +1,2 @@ #!/bin/bash -cp /etc/pki/tls/certs/ca-bundle.crt /sysroot/etc/pki/tls/certs/ +cat /etc/pki/tls/certs/ca-bundle.crt > /sysroot/etc/pki/tls/certs/