Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue-166 SharedVM get and update in types v1 #186

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func main() {
glog.Fatal(err)
}

vmServer, err := vmserver.NewVMServer(authnClient, authrClient, hfClient, hfInformerFactory, ctx)
vmServer, err := vmserver.NewVMServer(authnClient, authrClient, acClient, hfClient, hfInformerFactory, ctx)
if err != nil {
glog.Fatal(err)
}
Expand Down
18 changes: 17 additions & 1 deletion v3/pkg/apis/hobbyfarm.io/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type VirtualMachineList struct {
metav1.ListMeta `json:"metadata"`
Items []VirtualMachine `json:"items"`
}

// Todo isSharedVM Enam?
type VirtualMachineSpec struct {
VirtualMachineTemplateId string `json:"vm_template_id"`
SshUsername string `json:"ssh_username"`
Expand All @@ -41,8 +41,16 @@ type VirtualMachineSpec struct {
UserId string `json:"user"`
Provision bool `json:"provision"`
VirtualMachineSetId string `json:"vm_set_id"`
VirtualMachineType VirtualMachineType `json:"vm_type"`
}

type VirtualMachineType string

const (
VirtualMachineTypeUser VirtualMachineType = "User"
VirtualMachineTypeShared VirtualMachineType = "Shared"
)

type VirtualMachineStatus struct {
Status VmStatus `json:"status"` // default is nothing, but could be one of the following: readyforprovisioning, provisioning, running, terminating
Allocated bool `json:"allocated"`
Expand Down Expand Up @@ -474,6 +482,14 @@ type ScheduledEventSpec struct {
Printable bool `json:"printable"`
Scenarios []string `json:"scenarios"`
Courses []string `json:"courses"`
SharedVirtualMachines []SharedVirtualMachine `json:"shared_vms"`
}

type SharedVirtualMachine struct {
VMId string `json:"vmId"`
Name string `json:"name"`
Environment string `json:"environment"`
VMTemplate string `json:"vmTemplate"`
}

type ScheduledEventStatus struct {
Expand Down
106 changes: 104 additions & 2 deletions v3/pkg/controllers/scheduledevent/scheduledeventcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,101 @@ func (s ScheduledEventController) finishSessionsFromScheduledEvent(se *hfv1.Sche
return nil
}

func (s ScheduledEventController) CreateSharedVM(se *hfv1.ScheduledEvent) error {
for i := 0; i < len(se.Spec.SharedVirtualMachines); i++ {
sharedVM := &se.Spec.SharedVirtualMachines[i]
// if sharedVM are provision (have VMId) continue, if new(empty VMId) create VM
if sharedVM.VMId != "" {
continue
}
genName := fmt.Sprintf("shared-%s-%08x", se.Name, rand.Uint32())
sharedVM.VMId = genName
vm := &hfv1.VirtualMachine{
ObjectMeta: metav1.ObjectMeta{
Name: genName,
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: "hobbyfarm.io/v1",
Kind: "ScheduledEvent",
Name: se.Name,
UID: se.UID,
},
},
Labels: map[string]string{
"dynamic": "false",
"shared": "true",
util2.EnvironmentLabel: sharedVM.Environment,
"bound": "true",
"ready": "false",
util2.VirtualMachineTemplate: sharedVM.VMTemplate,
util2.ScheduledEventLabel: se.Name,
},
},
Spec: hfv1.VirtualMachineSpec{
VirtualMachineTemplateId: sharedVM.VMTemplate,
SecretName: "",
Protocol: "ssh", //default protocol is ssh
VirtualMachineClaimId: "",
UserId: "",
Provision: true,
VirtualMachineSetId: "",
VirtualMachineType: hfv1.VirtualMachineTypeShared, //"Shared"
},
}

environment, err := s.hfClientSet.HobbyfarmV1().Environments(util2.GetReleaseNamespace()).Get(s.ctx, sharedVM.Environment, metav1.GetOptions{})
if err != nil {
return err
}

vmt, err := s.hfClientSet.HobbyfarmV1().VirtualMachineTemplates(util2.GetReleaseNamespace()).Get(s.ctx, sharedVM.VMTemplate, metav1.GetOptions{})
if err != nil {
glog.Errorf("error getting vmt %v", err)
return err
}

config := util2.GetVMConfig(environment, vmt)

protocol, exists := config["protocol"]
if exists {
vm.Spec.Protocol = protocol
}

sshUser, exists := config["ssh_username"]
if exists {
vm.Spec.SshUsername = sshUser
}

// extra label to indicate external provisioning so tfpcontroller ignores this request //
if provisionMethod, ok := environment.Annotations["hobbyfarm.io/provisioner"]; ok {
vm.Labels["hobbyfarm.io/provisioner"] = provisionMethod
vm.Spec.Provision = false
}

createdVM, err := s.hfClientSet.HobbyfarmV1().VirtualMachines(util2.GetReleaseNamespace()).Create(s.ctx, vm, metav1.CreateOptions{})
if err != nil {
return err
}
glog.V(4).Infof("create sharedVM %s ", createdVM.Name)

createdVM.Status = hfv1.VirtualMachineStatus{
Status: hfv1.VmStatusRFP,
Allocated: true,
Tainted: false,
WsEndpoint: environment.Spec.WsEndpoint,
EnvironmentId: environment.Name,
PublicIP: "",
PrivateIP: "",
}

_, err = s.hfClientSet.HobbyfarmV1().VirtualMachines(util2.GetReleaseNamespace()).UpdateStatus(s.ctx, createdVM, metav1.UpdateOptions{})
if err != nil {
return err
}
}
return nil
}

func (s ScheduledEventController) provisionScheduledEvent(templates *hfv1.VirtualMachineTemplateList, se *hfv1.ScheduledEvent) error {
glog.V(6).Infof("ScheduledEvent %s is ready to be provisioned", se.Name)
// start creating resources related to this
Expand All @@ -292,6 +387,13 @@ func (s ScheduledEventController) provisionScheduledEvent(templates *hfv1.Virtua
e.g. --> glog.Errorf("we are overprovisioning this environment %s by CPU...
*/


//create shared VM for ScheduledEvent
err_vm := s.CreateSharedVM(se)
if err_vm != nil {
return err_vm
}

// begin by calculating what is currently being used in the environment
for envName, vmtMap := range se.Spec.RequiredVirtualMachines {
// get the environment we're provisioning into (envName)
Expand Down Expand Up @@ -439,8 +541,8 @@ func (s ScheduledEventController) provisionScheduledEvent(templates *hfv1.Virtua

retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {

seToUpdate, err := s.hfClientSet.HobbyfarmV1().ScheduledEvents(util2.GetReleaseNamespace()).Get(s.ctx, se.Name, metav1.GetOptions{})

//seToUpdate, err := s.hfClientSet.HobbyfarmV1().ScheduledEvents(util2.GetReleaseNamespace()).Get(s.ctx, se.Name, metav1.GetOptions{})
seToUpdate, err := s.hfClientSet.HobbyfarmV1().ScheduledEvents(util2.GetReleaseNamespace()).Update(s.ctx, se, metav1.UpdateOptions{})
if err != nil {
return err
}
Expand Down
84 changes: 81 additions & 3 deletions v3/pkg/scheduledeventserver/scheduledevent.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"github.com/golang/glog"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/util/retry"
)

Expand Down Expand Up @@ -280,7 +282,16 @@ func (s ScheduledEventServer) CreateFunc(w http.ResponseWriter, r *http.Request)
return
}
}

shared_vmsRaw := r.PostFormValue("shared_vms")
shared_vms := []hfv1.SharedVirtualMachine{} // must be declared this way so as to JSON marshal into [] instead of null
if shared_vmsRaw != "" {
err = json.Unmarshal([]byte(shared_vmsRaw), &shared_vms)
if err != nil {
glog.Errorf("error while unmarshalling shared_vms %v", err)
util2.ReturnHTTPMessage(w, r, 500, "internalerror", "error parsing")
return
}
}
scheduledEvent := &hfv1.ScheduledEvent{}
random := util2.RandStringRunes(16)
scheduledEvent.Name = "se-" + util2.GenerateResourceName("se", random, 10)
Expand All @@ -303,6 +314,10 @@ func (s ScheduledEventServer) CreateFunc(w http.ResponseWriter, r *http.Request)
scheduledEvent.Spec.Courses = courses
}

if shared_vmsRaw != "" {
scheduledEvent.Spec.SharedVirtualMachines = shared_vms
}

if restrictionDisabled {
scheduledEvent.Spec.RestrictedBind = false
} else {
Expand Down Expand Up @@ -376,6 +391,7 @@ func (s ScheduledEventServer) UpdateFunc(w http.ResponseWriter, r *http.Request)
onDemandRaw := r.PostFormValue("on_demand")
restrictionDisabledRaw := r.PostFormValue("disable_restriction")
printableRaw := r.PostFormValue("printable")
shared_vmsRaw := r.PostFormValue("shared_vms")

if name != "" {
scheduledEvent.Spec.Name = name
Expand Down Expand Up @@ -415,6 +431,56 @@ func (s ScheduledEventServer) UpdateFunc(w http.ResponseWriter, r *http.Request)
scheduledEvent.Spec.Courses = courses
}

if shared_vmsRaw != "" {
upd_shared_vms := []hfv1.SharedVirtualMachine{} // must be declared this way so as to JSON marshal into [] instead of null

err = json.Unmarshal([]byte(shared_vmsRaw), &upd_shared_vms)
if err != nil {
glog.Errorf("error while unmarshalling shared_vms %v", err)
// util.ReturnHTTPMessage(w, r, 500, "internalerror", "error parsing")
return fmt.Errorf("bad")
}

//del from provisionedVM that in upd_sharedVM not present and add new from sharedVM
provisioned_shared_vms := scheduledEvent.Spec.SharedVirtualMachines
actual_shared_vms := []hfv1.SharedVirtualMachine{}
if len(provisioned_shared_vms) > 0 {
for _, provisioned_shared_vm := range provisioned_shared_vms {
isDelVM := true
for _, upd_shared_vm := range upd_shared_vms {
if provisioned_shared_vm.Name == upd_shared_vm.Name {
isDelVM = false
break
}
}
if isDelVM {
glog.Infof("del shared_vms %v", provisioned_shared_vm.Name)
s.hfClientSet.HobbyfarmV1().VirtualMachines(util2.GetReleaseNamespace()).Delete(s.ctx, provisioned_shared_vm.VMId, metav1.DeleteOptions{})
} else {
actual_shared_vms = append(actual_shared_vms, provisioned_shared_vm)
glog.Infof("add provisioned shared_vms %v", provisioned_shared_vm.Name)
}

}
for _, upd_shared_vm := range upd_shared_vms {
isAddVM := true
for _, actual_shared_vm := range actual_shared_vms {
if actual_shared_vm.Name == upd_shared_vm.Name {
isAddVM = false
break
}
}
if isAddVM {
actual_shared_vms = append(actual_shared_vms, upd_shared_vm)
glog.Infof("add upd shared_vms %v", upd_shared_vm.Name)
}
}
scheduledEvent.Spec.SharedVirtualMachines = actual_shared_vms
} else {
scheduledEvent.Spec.SharedVirtualMachines = upd_shared_vms
}
}

if scenariosRaw != "" {
scenarios := []string{} // must be declared this way so as to JSON marshal into [] instead of null
err = json.Unmarshal([]byte(scenariosRaw), &scenarios)
Expand Down Expand Up @@ -798,8 +864,20 @@ func (s ScheduledEventServer) deleteProgressFromScheduledEvent(se *hfv1.Schedule

func (s ScheduledEventServer) deleteVMSetsFromScheduledEvent(se *hfv1.ScheduledEvent) error {
// delete all vmsets corresponding to this scheduled event
err := s.hfClientSet.HobbyfarmV1().VirtualMachineSets(util2.GetReleaseNamespace()).DeleteCollection(s.ctx, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", util2.ScheduledEventLabel, se.Name),
req1, err := labels.NewRequirement("shared", selection.NotEquals, []string{"true"})
if err != nil {
return err
}
req2, err := labels.NewRequirement(util2.ScheduledEventLabel, selection.Equals, []string{se.Name})
if err != nil {
return err
}
selector := labels.NewSelector()
selector = selector.Add(*req1).Add(*req2)
selectorString := selector.String()

err = s.hfClientSet.HobbyfarmV1().VirtualMachineSets(util2.GetReleaseNamespace()).DeleteCollection(s.ctx, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: selectorString,
})
if err != nil {
return err
Expand Down
Loading
Loading