diff mbox series

[14/14] channel_curl: Introduce support for PATCH method

Message ID 20200914145712.4989-14-christian.storm@siemens.com
State Accepted
Headers show
Series [01/14] channel_curl: Make setting request_body symmetric | expand

Commit Message

Storm, Christian Sept. 14, 2020, 2:57 p.m. UTC
Signed-off-by: Christian Storm <christian.storm@siemens.com>
---
 corelib/channel_curl.c | 28 +++++++++++++++++++---------
 include/channel_curl.h |  1 +
 2 files changed, 20 insertions(+), 9 deletions(-)

Comments

Stefano Babic Sept. 15, 2020, 7:24 a.m. UTC | #1
Hi Christian,

On 14.09.20 16:57, Christian Storm wrote:
> Signed-off-by: Christian Storm <christian.storm@siemens.com>
> ---
>  corelib/channel_curl.c | 28 +++++++++++++++++++---------
>  include/channel_curl.h |  1 +
>  2 files changed, 20 insertions(+), 9 deletions(-)
> 

Is a new backend planned ? Hawkbit does not have in its DDI interface a
PATCH method. Just curious...

> diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
> index 5142c71..6521850 100644
> --- a/corelib/channel_curl.c
> +++ b/corelib/channel_curl.c
> @@ -767,7 +767,7 @@ static channel_op_res_t parse_reply(channel_data_t *channel_data, output_data_t
>  	return CHANNEL_OK;
>  }
>  
> -static channel_op_res_t channel_post_method(channel_t *this, void *data)
> +static channel_op_res_t channel_post_method(channel_t *this, void *data, int method)
>  {
>  	channel_curl_t *channel_curl = this->priv;
>  	assert(data != NULL);
> @@ -793,20 +793,29 @@ static channel_op_res_t channel_post_method(channel_t *this, void *data)
>  		goto cleanup_header;
>  	}
>  
> -	if ((curl_easy_setopt(channel_curl->handle, CURLOPT_POST, 1L) != CURLE_OK) ||
> -		(curl_easy_setopt(channel_curl->handle, CURLOPT_POSTFIELDS,
> -					channel_data->request_body) != CURLE_OK)) {
> +	CURLcode curl_result;
> +	if (method == CHANNEL_PATCH) {
> +		curl_result = curl_easy_setopt(channel_curl->handle, CURLOPT_CUSTOMREQUEST, "PATCH");
> +	} else {
> +		curl_result = curl_easy_setopt(channel_curl->handle, CURLOPT_POST, 1L);
> +	}
> +	if (curl_result != CURLE_OK) {
> +		result = CHANNEL_EINIT;
> +		ERROR("Set POST/PATCH channel method option failed.");
> +		goto cleanup_header;
> +	}
> +	if (curl_easy_setopt(channel_curl->handle, CURLOPT_POSTFIELDS, channel_data->request_body) != CURLE_OK) {
>  		result = CHANNEL_EINIT;
> -		ERROR("Set POST channel method option failed.");
> +		ERROR("Set POST/PATCH channel data option failed.");
>  		goto cleanup_header;
>  	}
>  	if (channel_data->debug) {
> -		TRACE("Posted to %s: %s", channel_data->url, channel_data->request_body);
> +		TRACE("POSTed/PATCHed to %s: %s", channel_data->url, channel_data->request_body);
>  	}
>  
>  	CURLcode curlrc = curl_easy_perform(channel_curl->handle);
>  	if (curlrc != CURLE_OK) {
> -		ERROR("Channel put operation failed (%d): '%s'", curlrc,
> +		ERROR("Channel POST/PATCH operation failed (%d): '%s'", curlrc,
>  		      curl_easy_strerror(curlrc));
>  		result = channel_map_curl_error(curlrc);
>  		goto cleanup_header;
> @@ -908,9 +917,10 @@ channel_op_res_t channel_put(channel_t *this, void *data)
>  	case CHANNEL_PUT:
>  		return channel_put_method(this, data);
>  	case CHANNEL_POST:
> -		return channel_post_method(this, data);
> +	case CHANNEL_PATCH:
> +		return channel_post_method(this, data, channel_data->method);
>  	default:
> -		TRACE("Channel method (POST, PUT) is not set !");
> +		TRACE("Channel method (POST, PUT, PATCH) is not set !");
>  		return CHANNEL_EINIT;
>  	}
>  }
> diff --git a/include/channel_curl.h b/include/channel_curl.h
> index 6b4f4da..c3418a5 100644
> --- a/include/channel_curl.h
> +++ b/include/channel_curl.h
> @@ -25,6 +25,7 @@ typedef enum {
>  	CHANNEL_GET,
>  	CHANNEL_POST,
>  	CHANNEL_PUT,
> +	CHANNEL_PATCH,
>  } channel_method_t;
>  
>  typedef enum {
> 

Best regards,
Stefano
Storm, Christian Sept. 15, 2020, 9:36 a.m. UTC | #2
Hi Stefano,

> > Signed-off-by: Christian Storm <christian.storm@siemens.com>
> > ---
> >  corelib/channel_curl.c | 28 +++++++++++++++++++---------
> >  include/channel_curl.h |  1 +
> >  2 files changed, 20 insertions(+), 9 deletions(-)
> > 
> 
> Is a new backend planned ? Hawkbit does not have in its DDI interface a
> PATCH method. Just curious...

Yes, indeed, too obvious, isn't it? :)

I'm currently implementing support for a new version of the Siemens
MindSphere Firmware Deployment Service [1] and this has deprecated
POST in favor of PATCH ― for some REST endpoints at least.

Mender.io also uses PATCH, e.g., for the /device/attributes REST
endpoint [2].

So, for eventually supporting both (and probably some proprietary
backends as well), I guess we need PATCH support.


However, my broader plan is to actually not write new suricatta modules
for particular backends but instead write a generic Lua suricatta module
in C that allows one to write the "business logic" for particular
backends in Lua. This generic suricatta Lua module provides the
infrastructure / binding to SWUpdate (core) to the Lua realm.
With "business logic" I mean the specific backend server handling like
REST API banging and state communication, i.e., all that is specific to
a particular backend. 
In essence it's the same story as we have with the ability to write
handlers in Lua ― just for suricatta.

The reason for this idea is a separation of means and control: In the
C suricatta module world, both are intertwined and convoluted. Having
the control logics in Lua and the means (in terms of the instrumentation
of SWUpdate core) nicely wrapped up for the Lua realm to make use of
separates those two, easing maintenance and hopefully lowering the bar
to integrate more backends faster into SWUpdate.


To get a bit more technical, the generic Lua suricatta module to be
written in C exposes a register() function to the Lua realm so that the
suricatta interface methods (include/suricatta/server.h) can be
implemented in Lua, alongside a few other wrappers in order to call
SWUpdate (core) functionality from within the Lua realm to, e.g., handle
persistent state and doing communication. Again, the same story as with
the Lua handlers.
Currently, the `swupdate_suricatta.lua` Lua module looks like this:
```lua
local suricatta = {
    sleep      = function(seconds) end,
    install    = function(ichannel, pchannel) end,
    download   = function(ichannel, pchannel, path) end,
    get_tmpdir = function() end,
}

suricatta.status =  {
    OK                  = 0,
    EERR                = 1,
    EBADMSG             = 2,
    EINIT               = 3,
    EACCES              = 4,
    EAGAIN              = 5,
    UPDATE_AVAILABLE    = 6,
    NO_UPDATE_AVAILABLE = 7,
    UPDATE_CANCELED     = 8,
    ID_REQUESTED        = 9,
}

suricatta.notify = {
    error    = function(message) end,
    trace    = function(message) end,
    debug    = function(message) end,
    info     = function(message) end,
    warn     = function(message) end,
    progress = function(message) end,
}

suricatta.pstate = {
    get   = function() end,
    save  = function(state) end,
    reset = function() end,
    OK            = '0',
    INSTALLED     = '1',
    TESTING       = '2',
    FAILED        = '3',
    NOT_AVAILABLE = '4',
    ERROR         = '5',
    WAIT          = '6',
    IN_PROGRESS   = '7',
}

suricatta.server = {
    register = function(name, functiont) end,
    HAS_PENDING_ACTION   = 0,
    INSTALL_UPDATE       = 1,
    SEND_TARGET_DATA     = 2,
    GET_POLLING_INTERVAL = 3,
    SERVER_START         = 4,
    SERVER_STOP          = 5,
    IPC                  = 6,
    PRINT_HELP           = 7,
}

suricatta.channel = {
    open = function(optiont)
        return {
            get          = function(options) end,
            install      = function(options) end,
            downloadonly = function(options, path) end,
            put          = function(options) end,
            close        = function() end,
        }
    end,
    content = {
        NONE = 0,
        JSON = 1,
        RAW  = 2,
    },
    method = {
        GET   = 0,
        POST  = 1,
        PUT   = 2,
        PATCH = 3,
    }
}

return suricatta
```


Kind regards,
   Christian

[1] https://developer.mindsphere.io/apis/edge-firmwaredeployment/api-firmwaredeployment-basics.html
[2] https://docs.mender.io/api/#device-api-device-inventory
Stefano Babic Sept. 15, 2020, 4:40 p.m. UTC | #3
Hi Christian,

On 15.09.20 11:36, Christian Storm wrote:
> Hi Stefano,
> 
>>> Signed-off-by: Christian Storm <christian.storm@siemens.com>
>>> ---
>>>   corelib/channel_curl.c | 28 +++++++++++++++++++---------
>>>   include/channel_curl.h |  1 +
>>>   2 files changed, 20 insertions(+), 9 deletions(-)
>>>
>>
>> Is a new backend planned ? Hawkbit does not have in its DDI interface a
>> PATCH method. Just curious...
> 
> Yes, indeed, too obvious, isn't it? :)
> 

;-)

> I'm currently implementing support for a new version of the Siemens
> MindSphere Firmware Deployment Service [1] and this has deprecated
> POST in favor of PATCH ― for some REST endpoints at least.
> 
> Mender.io also uses PATCH, e.g., for the /device/attributes REST
> endpoint [2].
> 
> So, for eventually supporting both (and probably some proprietary
> backends as well), I guess we need PATCH support.
> 

Ok, got it.

> 
> However, my broader plan is to actually not write new suricatta modules
> for particular backends but instead write a generic Lua suricatta module
> in C that allows one to write the "business logic" for particular
> backends in Lua. This generic suricatta Lua module provides the
> infrastructure / binding to SWUpdate (core) to the Lua realm.
> With "business logic" I mean the specific backend server handling like
> REST API banging and state communication, i.e., all that is specific to
> a particular backend.
> In essence it's the same story as we have with the ability to write
> handlers in Lua ― just for suricatta.

Yes, it is similar.

> 
> The reason for this idea is a separation of means and control: In the
> C suricatta module world, both are intertwined and convoluted. Having
> the control logics in Lua and the means (in terms of the instrumentation
> of SWUpdate core) nicely wrapped up for the Lua realm to make use of
> separates those two, easing maintenance and hopefully lowering the bar
> to integrate more backends faster into SWUpdate.

I do not know if this could be generally better - for example, the 
REST-API in Mender requires a different approach for authentication 
(quite as JSON Token), and I guess that we need several external Lua 
libraries, while on C could ve more straightforward. So I guess each 
backend should be evaluated and estimated which is the best way to 
implement it.

> 
> 
> To get a bit more technical, the generic Lua suricatta module to be
> written in C exposes a register() function to the Lua realm so that the
> suricatta interface methods (include/suricatta/server.h) can be
> implemented in Lua,

Ok - so the polling server (suricatta.c) can call the specific backend 
implementation, that is in Lua if so specified.

I just like to have the same features we have now, for example streaming 
should still work with the Lua backend.

> alongside a few other wrappers in order to call
> SWUpdate (core) functionality from within the Lua realm to, e.g., handle
> persistent state and doing communication. Again, the same story as with
> the Lua handlers.
> Currently, the `swupdate_suricatta.lua` Lua module looks like this:
> ```lua
> local suricatta = {
>      sleep      = function(seconds) end,
>      install    = function(ichannel, pchannel) end,
>      download   = function(ichannel, pchannel, path) end,
>      get_tmpdir = function() end,
> }
> 
> suricatta.status =  {
>      OK                  = 0,
>      EERR                = 1,
>      EBADMSG             = 2,
>      EINIT               = 3,
>      EACCES              = 4,
>      EAGAIN              = 5,
>      UPDATE_AVAILABLE    = 6,
>      NO_UPDATE_AVAILABLE = 7,
>      UPDATE_CANCELED     = 8,
>      ID_REQUESTED        = 9,
> }
> 
> suricatta.notify = {
>      error    = function(message) end,
>      trace    = function(message) end,
>      debug    = function(message) end,
>      info     = function(message) end,
>      warn     = function(message) end,
>      progress = function(message) end,
> }
> 
> suricatta.pstate = {
>      get   = function() end,
>      save  = function(state) end,
>      reset = function() end,
>      OK            = '0',
>      INSTALLED     = '1',
>      TESTING       = '2',
>      FAILED        = '3',
>      NOT_AVAILABLE = '4',
>      ERROR         = '5',
>      WAIT          = '6',
>      IN_PROGRESS   = '7',
> }
> 
> suricatta.server = {
>      register = function(name, functiont) end,
>      HAS_PENDING_ACTION   = 0,
>      INSTALL_UPDATE       = 1,
>      SEND_TARGET_DATA     = 2,
>      GET_POLLING_INTERVAL = 3,
>      SERVER_START         = 4,
>      SERVER_STOP          = 5,
>      IPC                  = 6,
>      PRINT_HELP           = 7,
> }
> 
> suricatta.channel = {
>      open = function(optiont)
>          return {
>              get          = function(options) end,
>              install      = function(options) end,
>              downloadonly = function(options, path) end,
>              put          = function(options) end,
>              close        = function() end,
>          }
>      end,
>      content = {
>          NONE = 0,
>          JSON = 1,
>          RAW  = 2,
>      },
>      method = {
>          GET   = 0,
>          POST  = 1,
>          PUT   = 2,
>          PATCH = 3,
>      }
> }
> 
> return suricatta
> ```
> 
> 
> Kind regards,
>     Christian

Best regards,
Stefano
Storm, Christian Sept. 16, 2020, 8:16 a.m. UTC | #4
Hi Stefano,


> > > > Signed-off-by: Christian Storm <christian.storm@siemens.com>
> > > > ---
> > > >   corelib/channel_curl.c | 28 +++++++++++++++++++---------
> > > >   include/channel_curl.h |  1 +
> > > >   2 files changed, 20 insertions(+), 9 deletions(-)
> > > > 
> > > 
> > > Is a new backend planned ? Hawkbit does not have in its DDI interface a
> > > PATCH method. Just curious...
> > 
> > Yes, indeed, too obvious, isn't it? :)
> > 
> 
> ;-)
> 
> > I'm currently implementing support for a new version of the Siemens
> > MindSphere Firmware Deployment Service [1] and this has deprecated
> > POST in favor of PATCH ― for some REST endpoints at least.
> > 
> > Mender.io also uses PATCH, e.g., for the /device/attributes REST
> > endpoint [2].
> > 
> > So, for eventually supporting both (and probably some proprietary
> > backends as well), I guess we need PATCH support.
> > 
> 
> Ok, got it.
> 
> > 
> > However, my broader plan is to actually not write new suricatta modules
> > for particular backends but instead write a generic Lua suricatta module
> > in C that allows one to write the "business logic" for particular
> > backends in Lua. This generic suricatta Lua module provides the
> > infrastructure / binding to SWUpdate (core) to the Lua realm.
> > With "business logic" I mean the specific backend server handling like
> > REST API banging and state communication, i.e., all that is specific to
> > a particular backend.
> > In essence it's the same story as we have with the ability to write
> > handlers in Lua ― just for suricatta.
> 
> Yes, it is similar.
> 
> > 
> > The reason for this idea is a separation of means and control: In the
> > C suricatta module world, both are intertwined and convoluted. Having
> > the control logics in Lua and the means (in terms of the instrumentation
> > of SWUpdate core) nicely wrapped up for the Lua realm to make use of
> > separates those two, easing maintenance and hopefully lowering the bar
> > to integrate more backends faster into SWUpdate.
> 
> I do not know if this could be generally better - for example, the REST-API in
> Mender requires a different approach for authentication (quite as JSON Token),
> and I guess that we need several external Lua libraries, while on C could ve
> more straightforward. So I guess each backend should be evaluated and
> estimated which is the best way to implement it.

It's not about better or worse, it's about having options :)

I don't quite like the idea to pull in (external) Lua libraries for
this, to be honest. If there is a need for functionality not available
in the Lua realm to suricatta modules written in Lua, the same need
would be there if we code the suricatta module in C instead. Then, we
could as well code this missing functionality in C and (additionally)
make it available to the Lua realm. Then, both options (write it in
C and write it in Lua) can profit. The added overhead of also writing
a wrapper to the Lua realm is small to negligible, I think, since all
the infrastructure for doing so is already in SWUpdate.

Hence, I don't like the two options (write it in C or in Lua) to have
different feature sets in terms of what functionality they support and
can make use of from SWUpdate (core).
Instead, I'd like to have it like we have it now for the handlers: Both
are on par and it's not a technical (feature) choice of one over the
other.

That said, I do indeed think that the separation of means and control
can be beneficial to, e.g., maintenance, development speed, and
testability. After all, this is the reason for the idea as I've seen too
many projects where this would definitely have helped.

So, it's not about deprecating the option to write suricatta modules in
C nor about having an inferior option to write those in Lua ― which
makes no sense as nobody would use this option because of its inferiority.
It's actually ― as you said ― about then having a choice of whether
a backend support suricatta module is better implemented in Lua or C,
with their respective pros and cons.


> > To get a bit more technical, the generic Lua suricatta module to be
> > written in C exposes a register() function to the Lua realm so that the
> > suricatta interface methods (include/suricatta/server.h) can be
> > implemented in Lua,
> 
> Ok - so the polling server (suricatta.c) can call the specific backend
> implementation, that is in Lua if so specified.

Yes, exactly.


> I just like to have the same features we have now, for example streaming
> should still work with the Lua backend.

Absolutely. Both should be on a par.


> > alongside a few other wrappers in order to call
> > SWUpdate (core) functionality from within the Lua realm to, e.g., handle
> > persistent state and doing communication. Again, the same story as with
> > the Lua handlers.
> > Currently, the `swupdate_suricatta.lua` Lua module looks like this:
> > ```lua
> > local suricatta = {
> >      sleep      = function(seconds) end,
> >      install    = function(ichannel, pchannel) end,
> >      download   = function(ichannel, pchannel, path) end,
> >      get_tmpdir = function() end,
> > }
> > 
> > suricatta.status =  {
> >      OK                  = 0,
> >      EERR                = 1,
> >      EBADMSG             = 2,
> >      EINIT               = 3,
> >      EACCES              = 4,
> >      EAGAIN              = 5,
> >      UPDATE_AVAILABLE    = 6,
> >      NO_UPDATE_AVAILABLE = 7,
> >      UPDATE_CANCELED     = 8,
> >      ID_REQUESTED        = 9,
> > }
> > 
> > suricatta.notify = {
> >      error    = function(message) end,
> >      trace    = function(message) end,
> >      debug    = function(message) end,
> >      info     = function(message) end,
> >      warn     = function(message) end,
> >      progress = function(message) end,
> > }
> > 
> > suricatta.pstate = {
> >      get   = function() end,
> >      save  = function(state) end,
> >      reset = function() end,
> >      OK            = '0',
> >      INSTALLED     = '1',
> >      TESTING       = '2',
> >      FAILED        = '3',
> >      NOT_AVAILABLE = '4',
> >      ERROR         = '5',
> >      WAIT          = '6',
> >      IN_PROGRESS   = '7',
> > }
> > 
> > suricatta.server = {
> >      register = function(name, functiont) end,
> >      HAS_PENDING_ACTION   = 0,
> >      INSTALL_UPDATE       = 1,
> >      SEND_TARGET_DATA     = 2,
> >      GET_POLLING_INTERVAL = 3,
> >      SERVER_START         = 4,
> >      SERVER_STOP          = 5,
> >      IPC                  = 6,
> >      PRINT_HELP           = 7,
> > }
> > 
> > suricatta.channel = {
> >      open = function(optiont)
> >          return {
> >              get          = function(options) end,
> >              install      = function(options) end,
> >              downloadonly = function(options, path) end,
> >              put          = function(options) end,
> >              close        = function() end,
> >          }
> >      end,
> >      content = {
> >          NONE = 0,
> >          JSON = 1,
> >          RAW  = 2,
> >      },
> >      method = {
> >          GET   = 0,
> >          POST  = 1,
> >          PUT   = 2,
> >          PATCH = 3,
> >      }
> > }
> > 
> > return suricatta
> > ```


Besten Gruß,
   Christian
Stefano Babic Sept. 16, 2020, 8:33 a.m. UTC | #5
Hi Christian,

On 16.09.20 10:16, Christian Storm wrote:
> Hi Stefano,
> 
> 
>>>>> Signed-off-by: Christian Storm <christian.storm@siemens.com>
>>>>> ---
>>>>>   corelib/channel_curl.c | 28 +++++++++++++++++++---------
>>>>>   include/channel_curl.h |  1 +
>>>>>   2 files changed, 20 insertions(+), 9 deletions(-)
>>>>>
>>>>
>>>> Is a new backend planned ? Hawkbit does not have in its DDI interface a
>>>> PATCH method. Just curious...
>>>
>>> Yes, indeed, too obvious, isn't it? :)
>>>
>>
>> ;-)
>>
>>> I'm currently implementing support for a new version of the Siemens
>>> MindSphere Firmware Deployment Service [1] and this has deprecated
>>> POST in favor of PATCH ― for some REST endpoints at least.
>>>
>>> Mender.io also uses PATCH, e.g., for the /device/attributes REST
>>> endpoint [2].
>>>
>>> So, for eventually supporting both (and probably some proprietary
>>> backends as well), I guess we need PATCH support.
>>>
>>
>> Ok, got it.
>>
>>>
>>> However, my broader plan is to actually not write new suricatta modules
>>> for particular backends but instead write a generic Lua suricatta module
>>> in C that allows one to write the "business logic" for particular
>>> backends in Lua. This generic suricatta Lua module provides the
>>> infrastructure / binding to SWUpdate (core) to the Lua realm.
>>> With "business logic" I mean the specific backend server handling like
>>> REST API banging and state communication, i.e., all that is specific to
>>> a particular backend.
>>> In essence it's the same story as we have with the ability to write
>>> handlers in Lua ― just for suricatta.
>>
>> Yes, it is similar.
>>
>>>
>>> The reason for this idea is a separation of means and control: In the
>>> C suricatta module world, both are intertwined and convoluted. Having
>>> the control logics in Lua and the means (in terms of the instrumentation
>>> of SWUpdate core) nicely wrapped up for the Lua realm to make use of
>>> separates those two, easing maintenance and hopefully lowering the bar
>>> to integrate more backends faster into SWUpdate.
>>
>> I do not know if this could be generally better - for example, the REST-API in
>> Mender requires a different approach for authentication (quite as JSON Token),
>> and I guess that we need several external Lua libraries, while on C could ve
>> more straightforward. So I guess each backend should be evaluated and
>> estimated which is the best way to implement it.
> 
> It's not about better or worse, it's about having options :)
> 

Exactly - IMHO there will be cases where it is better to code in C, and
other cases where Lua is more suitable. As we have now for handlers.

> I don't quite like the idea to pull in (external) Lua libraries for
> this, to be honest.

Me too. This increases dependencies and I would like to avoid this.

> If there is a need for functionality not available
> in the Lua realm to suricatta modules written in Lua, the same need
> would be there if we code the suricatta module in C instead. Then, we
> could as well code this missing functionality in C and (additionally)
> make it available to the Lua realm. Then, both options (write it in
> C and write it in Lua) can profit. The added overhead of also writing
> a wrapper to the Lua realm is small to negligible, I think, since all
> the infrastructure for doing so is already in SWUpdate.

Fully agree.

> 
> Hence, I don't like the two options (write it in C or in Lua) to have
> different feature sets in terms of what functionality they support and
> can make use of from SWUpdate (core).

Exactly - goal is that we can have an option, but chossing one of them
does not mean to have limitations.

> Instead, I'd like to have it like we have it now for the handlers: Both
> are on par and it's not a technical (feature) choice of one over the
> other.

Right.

> 
> That said, I do indeed think that the separation of means and control
> can be beneficial to, e.g., maintenance, development speed, and
> testability. After all, this is the reason for the idea as I've seen too
> many projects where this would definitely have helped.

Fully agree.

> 
> So, it's not about deprecating the option to write suricatta modules in
> C nor about having an inferior option to write those in Lua ― which
> makes no sense as nobody would use this option because of its inferiority.
> It's actually ― as you said ― about then having a choice of whether
> a backend support suricatta module is better implemented in Lua or C,
> with their respective pros and cons.

+1

> 
> 
>>> To get a bit more technical, the generic Lua suricatta module to be
>>> written in C exposes a register() function to the Lua realm so that the
>>> suricatta interface methods (include/suricatta/server.h) can be
>>> implemented in Lua,
>>
>> Ok - so the polling server (suricatta.c) can call the specific backend
>> implementation, that is in Lua if so specified.
> 
> Yes, exactly.
> 
> 
>> I just like to have the same features we have now, for example streaming
>> should still work with the Lua backend.
> 
> Absolutely. Both should be on a par.
> 

Ok, we are perfectly in sync !

> 
>>> alongside a few other wrappers in order to call
>>> SWUpdate (core) functionality from within the Lua realm to, e.g., handle
>>> persistent state and doing communication. Again, the same story as with
>>> the Lua handlers.
>>> Currently, the `swupdate_suricatta.lua` Lua module looks like this:
>>> ```lua
>>> local suricatta = {
>>>      sleep      = function(seconds) end,
>>>      install    = function(ichannel, pchannel) end,
>>>      download   = function(ichannel, pchannel, path) end,
>>>      get_tmpdir = function() end,
>>> }
>>>
>>> suricatta.status =  {
>>>      OK                  = 0,
>>>      EERR                = 1,
>>>      EBADMSG             = 2,
>>>      EINIT               = 3,
>>>      EACCES              = 4,
>>>      EAGAIN              = 5,
>>>      UPDATE_AVAILABLE    = 6,
>>>      NO_UPDATE_AVAILABLE = 7,
>>>      UPDATE_CANCELED     = 8,
>>>      ID_REQUESTED        = 9,
>>> }
>>>
>>> suricatta.notify = {
>>>      error    = function(message) end,
>>>      trace    = function(message) end,
>>>      debug    = function(message) end,
>>>      info     = function(message) end,
>>>      warn     = function(message) end,
>>>      progress = function(message) end,
>>> }
>>>
>>> suricatta.pstate = {
>>>      get   = function() end,
>>>      save  = function(state) end,
>>>      reset = function() end,
>>>      OK            = '0',
>>>      INSTALLED     = '1',
>>>      TESTING       = '2',
>>>      FAILED        = '3',
>>>      NOT_AVAILABLE = '4',
>>>      ERROR         = '5',
>>>      WAIT          = '6',
>>>      IN_PROGRESS   = '7',
>>> }
>>>
>>> suricatta.server = {
>>>      register = function(name, functiont) end,
>>>      HAS_PENDING_ACTION   = 0,
>>>      INSTALL_UPDATE       = 1,
>>>      SEND_TARGET_DATA     = 2,
>>>      GET_POLLING_INTERVAL = 3,
>>>      SERVER_START         = 4,
>>>      SERVER_STOP          = 5,
>>>      IPC                  = 6,
>>>      PRINT_HELP           = 7,
>>> }
>>>
>>> suricatta.channel = {
>>>      open = function(optiont)
>>>          return {
>>>              get          = function(options) end,
>>>              install      = function(options) end,
>>>              downloadonly = function(options, path) end,
>>>              put          = function(options) end,
>>>              close        = function() end,
>>>          }
>>>      end,
>>>      content = {
>>>          NONE = 0,
>>>          JSON = 1,
>>>          RAW  = 2,
>>>      },
>>>      method = {
>>>          GET   = 0,
>>>          POST  = 1,
>>>          PUT   = 2,
>>>          PATCH = 3,
>>>      }
>>> }
>>>
>>> return suricatta
>>> ```
> 
> 

Gruss,
Stefano
diff mbox series

Patch

diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
index 5142c71..6521850 100644
--- a/corelib/channel_curl.c
+++ b/corelib/channel_curl.c
@@ -767,7 +767,7 @@  static channel_op_res_t parse_reply(channel_data_t *channel_data, output_data_t
 	return CHANNEL_OK;
 }
 
-static channel_op_res_t channel_post_method(channel_t *this, void *data)
+static channel_op_res_t channel_post_method(channel_t *this, void *data, int method)
 {
 	channel_curl_t *channel_curl = this->priv;
 	assert(data != NULL);
@@ -793,20 +793,29 @@  static channel_op_res_t channel_post_method(channel_t *this, void *data)
 		goto cleanup_header;
 	}
 
-	if ((curl_easy_setopt(channel_curl->handle, CURLOPT_POST, 1L) != CURLE_OK) ||
-		(curl_easy_setopt(channel_curl->handle, CURLOPT_POSTFIELDS,
-					channel_data->request_body) != CURLE_OK)) {
+	CURLcode curl_result;
+	if (method == CHANNEL_PATCH) {
+		curl_result = curl_easy_setopt(channel_curl->handle, CURLOPT_CUSTOMREQUEST, "PATCH");
+	} else {
+		curl_result = curl_easy_setopt(channel_curl->handle, CURLOPT_POST, 1L);
+	}
+	if (curl_result != CURLE_OK) {
+		result = CHANNEL_EINIT;
+		ERROR("Set POST/PATCH channel method option failed.");
+		goto cleanup_header;
+	}
+	if (curl_easy_setopt(channel_curl->handle, CURLOPT_POSTFIELDS, channel_data->request_body) != CURLE_OK) {
 		result = CHANNEL_EINIT;
-		ERROR("Set POST channel method option failed.");
+		ERROR("Set POST/PATCH channel data option failed.");
 		goto cleanup_header;
 	}
 	if (channel_data->debug) {
-		TRACE("Posted to %s: %s", channel_data->url, channel_data->request_body);
+		TRACE("POSTed/PATCHed to %s: %s", channel_data->url, channel_data->request_body);
 	}
 
 	CURLcode curlrc = curl_easy_perform(channel_curl->handle);
 	if (curlrc != CURLE_OK) {
-		ERROR("Channel put operation failed (%d): '%s'", curlrc,
+		ERROR("Channel POST/PATCH operation failed (%d): '%s'", curlrc,
 		      curl_easy_strerror(curlrc));
 		result = channel_map_curl_error(curlrc);
 		goto cleanup_header;
@@ -908,9 +917,10 @@  channel_op_res_t channel_put(channel_t *this, void *data)
 	case CHANNEL_PUT:
 		return channel_put_method(this, data);
 	case CHANNEL_POST:
-		return channel_post_method(this, data);
+	case CHANNEL_PATCH:
+		return channel_post_method(this, data, channel_data->method);
 	default:
-		TRACE("Channel method (POST, PUT) is not set !");
+		TRACE("Channel method (POST, PUT, PATCH) is not set !");
 		return CHANNEL_EINIT;
 	}
 }
diff --git a/include/channel_curl.h b/include/channel_curl.h
index 6b4f4da..c3418a5 100644
--- a/include/channel_curl.h
+++ b/include/channel_curl.h
@@ -25,6 +25,7 @@  typedef enum {
 	CHANNEL_GET,
 	CHANNEL_POST,
 	CHANNEL_PUT,
+	CHANNEL_PATCH,
 } channel_method_t;
 
 typedef enum {