Hello,
Some background: I am making custom Ubuntu Core images with a model assertion with a validation-set inside. In the model assertion I have set the validation-set to mode “prefer-enforce”, so that I can update the validation-set later inside the device:
...
"validation-sets" : [
{
"account-id" : "my-account-id",
"name" : "my-validation-set",
"sequence" : "3",
"mode" : "prefer-enforce"
}
],
...
After booting the image, I can successfully change the validation-set enforced on the device by running something like
$ snap validate --enforce --refresh my-account-id/my-validation-set=4
Enforced validation set "my-account-id/my-validation-set=4"
I want to do this action through the snapd REST API (because I want to run it from Landscape, as we don’t have access to the shell of our devices we want to update).
Here is the script I used
#!/usr/bin/env python3
# VARIABLES
validationset_name = "my-validation-set"
validationset_sequence = 4
validationset_accountid = "my-account-id"
# IMPORTS
import argparse
import requests
import socket
import os
# SNAPD SETUP
from urllib3.connection import HTTPConnection
from urllib3.connectionpool import HTTPConnectionPool
from requests.adapters import HTTPAdapter
class SnapdConnection(HTTPConnection):
def __init__(self):
super().__init__("localhost")
def connect(self):
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect("/run/snapd.socket")
class SnapdConnectionPool(HTTPConnectionPool):
def __init__(self):
super().__init__("localhost")
def _new_conn(self):
return SnapdConnection()
class SnapdAdapter(HTTPAdapter):
def get_connection(self, url, proxies=None):
return SnapdConnectionPool()
session = requests.Session()
session.mount("http://snapd/", SnapdAdapter())
base_url = "http://snapd/v2/"
## SCRIPT
print("Triggering validation set update")
headers = {
"Content-Type": "application/json"
}
payload = {
"action" : "apply",
"mode" : "enforce",
"sequence" : validationset_sequence,
}
url = f"{base_url}validation-sets/{validationset_accountid}/{validationset_name}"
print(f"Doing request to {url} with payload {payload}")
response = session.post(url, headers=headers, json=payload).json()
print(response)
However, in the snapd API the validate option seems to run into a validation check that prevents this validation from working:
charlee@946146c3-3e6d-4433-aa85-e7ffb1a5335a:~$ sudo python3 ./update-validation.py
Triggering validation set update
Doing request to http://snapd/v2/validation-sets/my-account-id/my-validation-set with payload {'action': 'apply', 'mode': 'enforce', 'sequence': 4}
{'type': 'error', 'status-code': 400, 'status': 'Bad Request', 'result': {'message': 'cannot enforce validation set: cannot enforce sequence 4 of validation set my-account-id/my-validation-set: only sequence 3 allowed by model'}}
Is this a bug? Or am I trying something that is not supported? (It seems like the refresh option is also not supported on the API )
How do you suggest to update validation-sets on IoT devices for which we have no shell access?
I am doing this on Ubuntu Core 22 with snapd 2.63