sonata-nfv / son-mano-framework

SONATA's Service Platform MANO Framework
http://www.sonata-nfv.eu
Apache License 2.0
20 stars 13 forks source link

MANO Framework API To Trigger initial deployment by GK #33

Closed smendel closed 8 years ago

smendel commented 8 years ago

Define and implement a API for simple service deployment to be used by the GK Derived from: https://github.com/sonata-nfv/son-mano-framework/issues/23 see also https://github.com/sonata-nfv/son-gkeeper/issues/33

@jbonnet @shuaibsiddiqui @tsoenen @mpeuster

tsoenen commented 8 years ago

From the MANO point of view, a JSON(?) file containing the NSD should be posted on service.instance.create on RabbitMQ.

Wether the GK is directly connected with RabbitMQ, or a REST API to a GK Adapter is in between doesn't matter, the deployment trigger is receiving the NSD JSON on service.instance.create

mpeuster commented 8 years ago

@tsoenen exactly. The example package in son-schema contains the NSD as YAML. But this is a detail. If we have direct RabbitMQ or REST to RabbitMQ translation is something we should decide in todays call.

tsoenen commented 8 years ago

Is this where we'll have the GK <-> Mano framework discussion?

Looking at http://wiki.sonata-nfv.eu/index.php/NS_LifeCycle_Mgr_MSC_Simplified, I have a comment/question on step 4. Should the VNFDs be included in the mesage on service.instance.create? If this message contains both NSD and VNFDs, it implies that the GK needs to determine what the VNFDs in a NSD are when the GK gets a deploy request from a user. I don't know how easy it is to send multiple yaml files together in a RabbitMQ message, but it is probably more complex than sending just 1.

Therefore, I would propose that service.instance.create just contains the NSD yaml file. The SLM reads this and asks the gatekeeper for the specific VNFDs one by one (function.descriptor topic). This would prevent the GK from looking inside a NSD to determine what the VNFDs are and it would prevent combining multiple yaml files in the same RabbitMQ message. It would require the GK to be able to pass VNFDs along (which is not new, right?).

jbonnet commented 8 years ago

Hi @tsoenen, the idea of the GK passing the whole thing (NSD + VNFDs) was to keep all the entities as independent as possible. I didn't think of exactly how to do it (and you're right, it's more complex than just passing one NSD), but I think it's manageable. The GK looks within the NSD when it receives the package, anyway, to store the VNFDs in the Catalogue

mpeuster commented 8 years ago

It is true that embedding multiple YAML files inside a single message is a bit more work but I think it is still easier than our other options (if we request them, the GK and SLM has to implement this request mechanism etc.).

As a Python guy I would simply embed each YAML file (which are Python dictionaries after parsing) into an global dictionary with keys: nds/vnfd1/vnfd2/... etc. dump this to a YAML (or even JSON) string and publish the message. The receiver can parse it and access the sub-directories. I assume Ruby can do it the same way.

@jbonnet During todays call the majority of people was in favor of directly sending RabbitMQ messages to/from the GK to the MANO framework. Would this option be ok for you (cf. sonata-nfv/son-gkeeper/issues/33)?

tsoenen commented 8 years ago

@jbonnet @mpeuster , ok! So, can we agree on the following structure of the yaml file that the GK will send to the Mano Framework?

---
NSD:
        descriptor_version:
        ...
VNFD1:
        descriptor_version:
        ...
VNFD2:
        descriptor_version:
        ...

For a full detailed yaml file of NSD and VNFDs, see Michael's examples on son/schema. From a 'receiving in python' point-of-view, this structure would be easily handled. From a 'sending in ruby' point-of-view, the YAML package in Ruby has a load and a dump function to convert a yaml file into a hash and vice versa. So it would come down to converting NSD/VNFDs yaml to a hash, combine these in a global hash and convert back to yaml.

mpeuster commented 8 years ago

@tsoenen I agree to use this as working assumption for our first version. Message should be published to the topic service.instance.create.

Which kind of reply (after service start/for errors) do you like to have? Service instance UUID? More?

I would publish the replies to the same topic.

tsoenen commented 8 years ago

Maybe, the request message from the GK to the MANO Framework needs an additional field:

---
Reference:
        request_id:
NSD:
        descriptor_version:
        ...
VNFD1:
        descriptor_version:
        ...
VNFD2:
        descriptor_version:
        ...

This would help the GK in its bookkeeping I guess, when the reply comes. Does the GK needs to know UUID's for specific VNFs (is UUID the correct term here?) for maybe monitoring purposes? The reply could look like:

---
Reference:
        request_id:
Service:
        service_uuid:
        status:
VNFD1:
        vnf_name:
        vnf_uuid:
VNFD2:
        vnf_name:
        vnf_uuid:

Naming might be off. vnf_name could also be vnf_id (whatever is in the VNFD, it should be the same as that). The GK knowing specific id's for the vnf instances enables the GK to share this with the user, who can use this to access monitoring data from a repo. Or is their a different mechanism to provide the user with this?

@mpeuster : I can take the implementation of the SLM for my account, to share some of the development load. I can start working on it on monday, so I hope to have something running by monday night.

mpeuster commented 8 years ago

@tsoenen We don't need the request ID as an extra field. This request / reply matching ID should be stored in the correlation_id field of the message properties (This is how the messaging abstraction in son-mano-base does it and follows the official RabbitMQ docu).

see:

Would be great if you can start the implementation. I already prepared this:

Wich now expects only a incoming message and does not automatically generate a reply. For this we should use register_async_endpoint(self, callback_ptr, topic) from the messaging.pythat does exactly this: Gets a message, calls the given callback function (in a new thread), and generates a response when the callback function returns. This would hide all the correlation_id handling etc. from you.

But you can of course do it manually if you want.

tsoenen commented 8 years ago

@mpeuster : Are you proposing to use register_async_endpoint(self, callback_ptr, topic) for the message from GK --> SLM, or from SLM --> Infra Adaptor, or for both (nested)?

If register_async_endpoint(self, callback_ptr, topic) is used, how is the response generated? Can we control what is in the message of the response?

mpeuster commented 8 years ago

@tsoenen for GK --> SLM.

The response message is automatically generated from the return value of the function given by callback_ptr.

The message system expects a string as return value (e.g. generated by json.dumps) from callback_ptr(). This string is then used as message body of the response message.

mpeuster commented 8 years ago

The current version, however, uses:

self.manoconn.register_notification_endpoint(
            self.on_gk_service_instance_create,  # function called when message received

Instead of register_async_endpoint(self, callback_ptr, topic) . The difference is that it does not automatically generate a response. You would have to do something like self.manoconn.notify(topic, message) to generate a response message on your own.

tsoenen commented 8 years ago

@mpeuster : Allrite. This raises another question. The GK contacts the SLM, which triggers register_async_endpoint() on the SLM, which triggers the callback function self.on_gk_service_instance_create. In this callback function, the SLM needs to send a message to the infra. adaptor (with call_async() ?), to which the infra adaptor needs to reply. When call_async() is called, self.on_gk_service_instance_create() continues, reaching the return (which triggers the response to the GK) before the Infra. Adaptor has replied to the SLM. Is the idea to wait after the call_async() for the response of the GK before continuing with self.on_gk_service_instance.create()? If yes, how do we do this?

mpeuster commented 8 years ago

@tsoenen

(1) No, register_async_endpoint() has to be called when the SLM starts in order to start to "listen" to the create topic to wich the GK request is published.

(2) Right, call_async would not wait automatically since it is an async interface. The question is if we really want to wait for the complete service instance to be created or if we directly send a return message so that the GK knows that the "instantiation procedure" is RUNNING. We could then publish an additional notification to the GK when the instantiation process finally finishes and the service is up ("instantiation procedure" FINISHED).

tsoenen commented 8 years ago

@mpeuster : (1) Yes, bad wording on my side (2) Ok

Thanks!

tsoenen commented 8 years ago

Hi all! I've extended the SLM code that @mpeuster had provided. It reacts to a message from the GK (locally dummied by the example plugin), translates the incoming message (that is formatted like discussed above) and it sends it to the Infra. Adaptor on the infrastructure.service.deploy topic (which is received, again by a dummy). The translation itself is still buggy, but I won't be able to solve that before wednesday (I'm currently unable to build the dockerfiles from home due to some firewall/proxy setting, and I'm out of the office tomorrow), so the pull request will be for wednesday around noon.

Concerning the translation: In the 'forwarding_graph' part of the NSD (see the example of Michael on SON-SCHEMA), the VNFs are referenced with their 'vnf_id'. In the exampel VNFDs, the VNFS are referenced with their 'vnf_name'. These two are not a 1-to-1 map of eachother, making it impossible for the Infra. Adaptor to determine which vnf image is which vnf in the forwarding graph. Some options to fix this: (1) The SLM fixes this by replacing the 'vnf_id' in the forwarding graph by the 'vnf_name' it can determine from other parts of the NSD (2) The NSD changes, and uses 'vnf_name' in the forwarding graph (3) The VNFD changes, and uses 'vnf_id' instead of 'vnf_name', or uses both

I think (3) is the cleanest option.

Another thing, we need to interact with the SLM <--> Infra Adaptor task force (which I can do, since I'm part of both) to determine how the Infra. Adaptor desires to receive the deployment info.

Also, I won't be able to join the calls on Tuesday.

mpeuster commented 8 years ago

@tsoenen Tanks for this work Thomas. Can we look into your changes somewhere? Your private fork? Would help me to prepare for today's call.

BTW: +1 for (3)

mpeuster commented 8 years ago

To prepare for the GK <-> MANO call today, I tried to collect the definitions we have so far in our standard Wiki Message definition format.

You can find it here:

Especially the reply, which might be divided into multiple messages to indicate state transitions has still to be defined.

shuaibsiddiqui commented 8 years ago

@tsoenen : vnf_id translation: The SP-Catalogue generates UUIDs for the NSD and the VNFDs. The UUID generated for an VNFD will be stored in the vnf_id under network_functions in the NSD. I think these vnf_id could/should be used to resolve the issue.

mbredel commented 8 years ago

In general, I think the VNFDs (and any other descriptor, like the NSD) should be write once - at the developer side - only. Thus, the SP should never change the VNFD. We can, of course, have additional information aside with it.

The whole idea of the VNFDs as they are right now, is to have them as human-readable as possible. Introducing UUID for example contradicts that goal. Moreover, if someone, say the developer, downloads the VNFD again, e.g. for debugging, it might be hard to track the changes the SP has made.

Therefore, I would vote for NOT changing the VNFDs and NSDs on the SP side.

@tsoenen : I got a bit lost in your explanation regarding 'vnf_id' and 'vnf_name' :-) The VNFD is uniquely identified by vnf_group, vnf_name, and vnf_version. This triple can be used, e.g. to download the VNFD from a catalog (SP internal, there might be an additional UUID that identifies the descriptor). Within the NSD a developer can have a NSD-internal ID that can be used inside the NSD to identify the VNFDs. Likewise within the VNFD we have VNFD-internal IDs to identify the VDUs. I guess you have to parse and traverse the descriptors to collect the needed information

@tsoenen : There was an error in the example VNFDs (iperf, firewall, tcpdump) regarding the VNFD-internal IDs. In fact, the references were not used correctly. Maybe the newer versions solve you problem already?

mpeuster commented 8 years ago

@tsoenen @jbonnet @smendel

I updated the GK <-> MANO framework message definition like agreed in the call today: http://wiki.sonata-nfv.eu/index.php/MANO_Messages_Service

We still have a async. RabbitMQ based messaging pattern:

  1. GK send request to SLM
  2. SLM checks if request is ok (e.g. NSD is included) and replies with a simple response message to indicate that the service instantiation procedure was started
  3. SLM sends an additional notification to the GK to indicate that the service instantiation was finalized

We agreed that the final notification will contain all information that are also written to the repository (NSR, VNFRs, ...) so that the GK has not to poll the repo again.

@tsoenen You can stick with your current implementation for request + response, and you can use .publish(...) to generate the final notification.

Please feel free to extend the message definition on the wikipage if you feel that there are field missing.

mpeuster commented 8 years ago

@tsoenen I forgot one thing: Maybe we should move your "dummy" trigger procedures from the example plugin to a test script bundled with the SLM (/test/...) to keep the example plugin slim. I plan to do the same for the plugin manager tests I am working on. This helps the CI to validate the correctness of the interfaces.

tsoenen commented 8 years ago

@mpeuster : Hi Manuel! Concerning the message properties, which are automatically set? Is app_id automatically set? is the content_type default 'application/yaml'?

mpeuster commented 8 years ago

@tsoenen The app_id, etc. is automatically set. Content type default is "application/json" ... you can modify it by adding content_type="application/yaml"to your call_async(...) calls.

Instead of using .publish(...)for the second reply using .notify(....) makes more sense.

See: https://github.com/sonata-nfv/son-mano-framework/blob/master/son-mano-base/sonmanobase/messaging.py#L361

tsoenen commented 8 years ago

@mbredel : The Infra. Adaptor needs the forwarding graph of the service, and the images of the vnfs, to be able to deploy the service. At this point, we provide the Infra. Adaptor with this info by using the following yaml format:

forwarding_graph:
        ...
vnf_images:
        - vnf_id:
          url:
        - vnf_id:
          url:
        - ...

where the forwarding_graph part is an exact copy from the NSD. In the NSD, the fowarding_graph part references the vnfs (under 'constituents_vnfs') by using their 'vnf_id'. The second part of the yaml file above is built from the VNFDs. Since the forwarding_graph is using vnf_id as reference, vnf_images should do so as well, so the Infra. Adaptor is able to map the urls to the correct vnfs. In the VNFD, however, the vnf_id is not referenced, the vnf is referenced with vnf_name, vnf_version and vnf_group. So, in order to map the url to the vnf_id, there are two options:

(1): The SLM maps the vnf_name, vnf_group and vnf_version to vnf_id (based on the content in the NSD, under network_functions) (2): The VNFD adds vnf_id, or the NSD uses vnf_name, vnf_group and vnf_version in the forwarding_graph part.

I hope it makes more sense now. I think if a vnf can be referenced by a 'vnf_id', this should also be included in the descriptor of that vnf.

mbredel commented 8 years ago

@tsoenen I think I got your point. The general problem here is that the NSD and the VNFD are completely independent. That is, the VNFD might be provided by someone completely different from the one that provided the NSD. I am not sure how to enforce similar ideas (i.e. the vnf_id) across multiple descriptors. In fact, that is not intended.

However, I guess there is a solution built in the NSD already: The 'forwarding_graph' uses the 'vnf_id' of the NSD. And in the 'network_functions' section of the NSD there is the mapping of the 'vnf_id' to vnf_group, vnf_name, and vnf_version. Thus, the NSD actually uses your proposed solution (2) ... you "just" have to to the mapping :-)

See, for example, the vnf_firewall below

network_functions:
  - vnf_id: "vnf_firewall"
    vnf_group: "eu.sonata-nfv"
    vnf_name: "firewall-vnf"
    vnf_version: "0.1"
forwarding_graphs:
  - fg_id: "ns:fg01"
    number_of_endpoints: 2
    number_of_virtual_links: 4
    constituent_vnfs:
      - "vnf_iperf"
      - "vnf_firewall"
      - "vnf_tcpdump"

Does that help?

mbredel commented 8 years ago

And now that I read your previous message again ... you got that already :-D ... sorry ... Solution (1) ...

tsoenen commented 8 years ago

Allrite, solution (1) it is!