Can't create an unmanaged subnet with MAAS API


I’m trying to create a subnet that is not managed by maas.

According to the documentation, in the call POST /MAAS/api/2.0/subnets/, there’s a parameter managed (int), which can be set to 0 (false) or 1 (true).

It doesn’t matter which value I assign to it, it will be ignored.

How to reproduce it:

import oauth2
import httplib2
import uuid
import os
import binascii
import json

API_KEY = "xxxxxxxxxxxx:xxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxx"
[consumer_key, key, secret] = API_KEY.split(':')

BASE_URL = 'http://<ip>:5240/MAAS/api/2.0'

def api_maas(uri, method, data=None, message=None):
    token_uri = 'oauth_token_secret={}&oauth_token={}'
    token_str = token_uri.format(secret, key)
    resource_token = oauth2.Token.from_string(token_str)
    consumer_token = oauth2.Consumer(consumer_key, '')

    request = oauth2.Request.from_consumer_and_token(
        parameters={'oauth_nonce': uuid.uuid4().hex}

        consumer_token, resource_token)

    url = '%s%s' % (BASE_URL, uri)
    headers = request.to_header()

    http = httplib2.Http()
    if data is not None:
        body, c_t = encode_multipart_formdata(data)
        headers['content-type'] = c_t
        body = None
    (r, c) = http.request(url, method, body=body, headers=headers)

    if r.status >= 200 and r.status < 300:
        return c

def encode_multipart_formdata(fields):
    boundary = binascii.hexlify(os.urandom(16)).decode('ascii')

    body = (
                "Content-Disposition: form-data; name=\"%s\"\r\n"
                "%s\r\n" % (boundary, field, value)
                for field, value in fields.items()) +
        "--%s--\r\n" % boundary

    content_type = "multipart/form-data; boundary=%s" % boundary

    return body, content_type

data = {
    'cidr': '',
    'name': 'test',
    'description': '',
    'fabric': '0',
    'vid': 0,
    'gateway_ip': '',
    'rdns_mode': 0,
    'allow_dns': 1,
    'allow_proxy': 0,
    'dns_servers': '',
    'managed': 0

c = api_maas('/subnets/', 'POST', data=data)

print(json.dumps(json.loads(c), separators=(',',':'), sort_keys=True, indent=4))

This is the output:


The output shows: managed: true

Hmm, what happens if you try False instead of 0?

Same result!

As a note! If I enable dhcp on that vlan, I get an error because I haven’t set a dynamic reserved range, which is expected! BUT, after that error, the subnet is in managed: False state, which is weird

Thanks, I’m looking into this, along with which seems very similar.

After digging into the code and running some tests, I believe the bug is in the API documentation.

Instead of passing an integer, you should pass a boolean. Note that ‘0’ explicitly does not work (is interpreted as True), which is what your script will end up sending due to encode_multipart_formdata using %s. Instead if you pass in 'false' it is correctly interpreted as False